PageRenderTime 63ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/src/static/vendor/lodash/vendor/backbone/test/model.js

https://gitlab.com/pidlisnyi/lisbon
JavaScript | 1413 lines | 1261 code | 150 blank | 2 comment | 25 complexity | 5664e0dd67056a6760875ef9a4d40735 MD5 | raw file
  1. (function() {
  2. var ProxyModel = Backbone.Model.extend();
  3. var Klass = Backbone.Collection.extend({
  4. url: function() { return '/collection'; }
  5. });
  6. var doc, collection;
  7. QUnit.module('Backbone.Model', {
  8. beforeEach: function(assert) {
  9. doc = new ProxyModel({
  10. id: '1-the-tempest',
  11. title: 'The Tempest',
  12. author: 'Bill Shakespeare',
  13. length: 123
  14. });
  15. collection = new Klass();
  16. collection.add(doc);
  17. }
  18. });
  19. QUnit.test('initialize', function(assert) {
  20. assert.expect(3);
  21. var Model = Backbone.Model.extend({
  22. initialize: function() {
  23. this.one = 1;
  24. assert.equal(this.collection, collection);
  25. }
  26. });
  27. var model = new Model({}, {collection: collection});
  28. assert.equal(model.one, 1);
  29. assert.equal(model.collection, collection);
  30. });
  31. QUnit.test('initialize with attributes and options', function(assert) {
  32. assert.expect(1);
  33. var Model = Backbone.Model.extend({
  34. initialize: function(attributes, options) {
  35. this.one = options.one;
  36. }
  37. });
  38. var model = new Model({}, {one: 1});
  39. assert.equal(model.one, 1);
  40. });
  41. QUnit.test('initialize with parsed attributes', function(assert) {
  42. assert.expect(1);
  43. var Model = Backbone.Model.extend({
  44. parse: function(attrs) {
  45. attrs.value += 1;
  46. return attrs;
  47. }
  48. });
  49. var model = new Model({value: 1}, {parse: true});
  50. assert.equal(model.get('value'), 2);
  51. });
  52. QUnit.test('initialize with defaults', function(assert) {
  53. assert.expect(2);
  54. var Model = Backbone.Model.extend({
  55. defaults: {
  56. firstName: 'Unknown',
  57. lastName: 'Unknown'
  58. }
  59. });
  60. var model = new Model({'firstName': 'John'});
  61. assert.equal(model.get('firstName'), 'John');
  62. assert.equal(model.get('lastName'), 'Unknown');
  63. });
  64. QUnit.test('parse can return null', function(assert) {
  65. assert.expect(1);
  66. var Model = Backbone.Model.extend({
  67. parse: function(attrs) {
  68. attrs.value += 1;
  69. return null;
  70. }
  71. });
  72. var model = new Model({value: 1}, {parse: true});
  73. assert.equal(JSON.stringify(model.toJSON()), '{}');
  74. });
  75. QUnit.test('url', function(assert) {
  76. assert.expect(3);
  77. doc.urlRoot = null;
  78. assert.equal(doc.url(), '/collection/1-the-tempest');
  79. doc.collection.url = '/collection/';
  80. assert.equal(doc.url(), '/collection/1-the-tempest');
  81. doc.collection = null;
  82. assert.raises(function() { doc.url(); });
  83. doc.collection = collection;
  84. });
  85. QUnit.test('url when using urlRoot, and uri encoding', function(assert) {
  86. assert.expect(2);
  87. var Model = Backbone.Model.extend({
  88. urlRoot: '/collection'
  89. });
  90. var model = new Model();
  91. assert.equal(model.url(), '/collection');
  92. model.set({id: '+1+'});
  93. assert.equal(model.url(), '/collection/%2B1%2B');
  94. });
  95. QUnit.test('url when using urlRoot as a function to determine urlRoot at runtime', function(assert) {
  96. assert.expect(2);
  97. var Model = Backbone.Model.extend({
  98. urlRoot: function() {
  99. return '/nested/' + this.get('parentId') + '/collection';
  100. }
  101. });
  102. var model = new Model({parentId: 1});
  103. assert.equal(model.url(), '/nested/1/collection');
  104. model.set({id: 2});
  105. assert.equal(model.url(), '/nested/1/collection/2');
  106. });
  107. QUnit.test('underscore methods', function(assert) {
  108. assert.expect(5);
  109. var model = new Backbone.Model({foo: 'a', bar: 'b', baz: 'c'});
  110. var model2 = model.clone();
  111. assert.deepEqual(model.keys(), ['foo', 'bar', 'baz']);
  112. assert.deepEqual(model.values(), ['a', 'b', 'c']);
  113. assert.deepEqual(model.invert(), {a: 'foo', b: 'bar', c: 'baz'});
  114. assert.deepEqual(model.pick('foo', 'baz'), {foo: 'a', baz: 'c'});
  115. assert.deepEqual(model.omit('foo', 'bar'), {baz: 'c'});
  116. });
  117. QUnit.test('chain', function(assert) {
  118. var model = new Backbone.Model({a: 0, b: 1, c: 2});
  119. assert.deepEqual(model.chain().pick('a', 'b', 'c').values().compact().value(), [1, 2]);
  120. });
  121. QUnit.test('clone', function(assert) {
  122. assert.expect(10);
  123. var a = new Backbone.Model({foo: 1, bar: 2, baz: 3});
  124. var b = a.clone();
  125. assert.equal(a.get('foo'), 1);
  126. assert.equal(a.get('bar'), 2);
  127. assert.equal(a.get('baz'), 3);
  128. assert.equal(b.get('foo'), a.get('foo'), 'Foo should be the same on the clone.');
  129. assert.equal(b.get('bar'), a.get('bar'), 'Bar should be the same on the clone.');
  130. assert.equal(b.get('baz'), a.get('baz'), 'Baz should be the same on the clone.');
  131. a.set({foo: 100});
  132. assert.equal(a.get('foo'), 100);
  133. assert.equal(b.get('foo'), 1, 'Changing a parent attribute does not change the clone.');
  134. var foo = new Backbone.Model({p: 1});
  135. var bar = new Backbone.Model({p: 2});
  136. bar.set(foo.clone().attributes, {unset: true});
  137. assert.equal(foo.get('p'), 1);
  138. assert.equal(bar.get('p'), undefined);
  139. });
  140. QUnit.test('isNew', function(assert) {
  141. assert.expect(6);
  142. var a = new Backbone.Model({foo: 1, bar: 2, baz: 3});
  143. assert.ok(a.isNew(), 'it should be new');
  144. a = new Backbone.Model({foo: 1, bar: 2, baz: 3, id: -5});
  145. assert.ok(!a.isNew(), 'any defined ID is legal, negative or positive');
  146. a = new Backbone.Model({foo: 1, bar: 2, baz: 3, id: 0});
  147. assert.ok(!a.isNew(), 'any defined ID is legal, including zero');
  148. assert.ok(new Backbone.Model().isNew(), 'is true when there is no id');
  149. assert.ok(!new Backbone.Model({id: 2}).isNew(), 'is false for a positive integer');
  150. assert.ok(!new Backbone.Model({id: -5}).isNew(), 'is false for a negative integer');
  151. });
  152. QUnit.test('get', function(assert) {
  153. assert.expect(2);
  154. assert.equal(doc.get('title'), 'The Tempest');
  155. assert.equal(doc.get('author'), 'Bill Shakespeare');
  156. });
  157. QUnit.test('escape', function(assert) {
  158. assert.expect(5);
  159. assert.equal(doc.escape('title'), 'The Tempest');
  160. doc.set({audience: 'Bill & Bob'});
  161. assert.equal(doc.escape('audience'), 'Bill & Bob');
  162. doc.set({audience: 'Tim > Joan'});
  163. assert.equal(doc.escape('audience'), 'Tim > Joan');
  164. doc.set({audience: 10101});
  165. assert.equal(doc.escape('audience'), '10101');
  166. doc.unset('audience');
  167. assert.equal(doc.escape('audience'), '');
  168. });
  169. QUnit.test('has', function(assert) {
  170. assert.expect(10);
  171. var model = new Backbone.Model();
  172. assert.strictEqual(model.has('name'), false);
  173. model.set({
  174. '0': 0,
  175. '1': 1,
  176. 'true': true,
  177. 'false': false,
  178. 'empty': '',
  179. 'name': 'name',
  180. 'null': null,
  181. 'undefined': undefined
  182. });
  183. assert.strictEqual(model.has('0'), true);
  184. assert.strictEqual(model.has('1'), true);
  185. assert.strictEqual(model.has('true'), true);
  186. assert.strictEqual(model.has('false'), true);
  187. assert.strictEqual(model.has('empty'), true);
  188. assert.strictEqual(model.has('name'), true);
  189. model.unset('name');
  190. assert.strictEqual(model.has('name'), false);
  191. assert.strictEqual(model.has('null'), false);
  192. assert.strictEqual(model.has('undefined'), false);
  193. });
  194. QUnit.test('matches', function(assert) {
  195. assert.expect(4);
  196. var model = new Backbone.Model();
  197. assert.strictEqual(model.matches({name: 'Jonas', cool: true}), false);
  198. model.set({name: 'Jonas', cool: true});
  199. assert.strictEqual(model.matches({name: 'Jonas'}), true);
  200. assert.strictEqual(model.matches({name: 'Jonas', cool: true}), true);
  201. assert.strictEqual(model.matches({name: 'Jonas', cool: false}), false);
  202. });
  203. QUnit.test('matches with predicate', function(assert) {
  204. var model = new Backbone.Model({a: 0});
  205. assert.strictEqual(model.matches(function(attr) {
  206. return attr.a > 1 && attr.b != null;
  207. }), false);
  208. model.set({a: 3, b: true});
  209. assert.strictEqual(model.matches(function(attr) {
  210. return attr.a > 1 && attr.b != null;
  211. }), true);
  212. });
  213. QUnit.test('set and unset', function(assert) {
  214. assert.expect(8);
  215. var a = new Backbone.Model({id: 'id', foo: 1, bar: 2, baz: 3});
  216. var changeCount = 0;
  217. a.on('change:foo', function() { changeCount += 1; });
  218. a.set({foo: 2});
  219. assert.equal(a.get('foo'), 2, 'Foo should have changed.');
  220. assert.equal(changeCount, 1, 'Change count should have incremented.');
  221. // set with value that is not new shouldn't fire change event
  222. a.set({foo: 2});
  223. assert.equal(a.get('foo'), 2, 'Foo should NOT have changed, still 2');
  224. assert.equal(changeCount, 1, 'Change count should NOT have incremented.');
  225. a.validate = function(attrs) {
  226. assert.equal(attrs.foo, void 0, 'validate:true passed while unsetting');
  227. };
  228. a.unset('foo', {validate: true});
  229. assert.equal(a.get('foo'), void 0, 'Foo should have changed');
  230. delete a.validate;
  231. assert.equal(changeCount, 2, 'Change count should have incremented for unset.');
  232. a.unset('id');
  233. assert.equal(a.id, undefined, 'Unsetting the id should remove the id property.');
  234. });
  235. QUnit.test('#2030 - set with failed validate, followed by another set triggers change', function(assert) {
  236. var attr = 0, main = 0, error = 0;
  237. var Model = Backbone.Model.extend({
  238. validate: function(attrs) {
  239. if (attrs.x > 1) {
  240. error++;
  241. return 'this is an error';
  242. }
  243. }
  244. });
  245. var model = new Model({x: 0});
  246. model.on('change:x', function() { attr++; });
  247. model.on('change', function() { main++; });
  248. model.set({x: 2}, {validate: true});
  249. model.set({x: 1}, {validate: true});
  250. assert.deepEqual([attr, main, error], [1, 1, 1]);
  251. });
  252. QUnit.test('set triggers changes in the correct order', function(assert) {
  253. var value = null;
  254. var model = new Backbone.Model;
  255. model.on('last', function(){ value = 'last'; });
  256. model.on('first', function(){ value = 'first'; });
  257. model.trigger('first');
  258. model.trigger('last');
  259. assert.equal(value, 'last');
  260. });
  261. QUnit.test('set falsy values in the correct order', function(assert) {
  262. assert.expect(2);
  263. var model = new Backbone.Model({result: 'result'});
  264. model.on('change', function() {
  265. assert.equal(model.changed.result, void 0);
  266. assert.equal(model.previous('result'), false);
  267. });
  268. model.set({result: void 0}, {silent: true});
  269. model.set({result: null}, {silent: true});
  270. model.set({result: false}, {silent: true});
  271. model.set({result: void 0});
  272. });
  273. QUnit.test('nested set triggers with the correct options', function(assert) {
  274. var model = new Backbone.Model();
  275. var o1 = {};
  276. var o2 = {};
  277. var o3 = {};
  278. model.on('change', function(__, options) {
  279. switch (model.get('a')) {
  280. case 1:
  281. assert.equal(options, o1);
  282. return model.set('a', 2, o2);
  283. case 2:
  284. assert.equal(options, o2);
  285. return model.set('a', 3, o3);
  286. case 3:
  287. assert.equal(options, o3);
  288. }
  289. });
  290. model.set('a', 1, o1);
  291. });
  292. QUnit.test('multiple unsets', function(assert) {
  293. assert.expect(1);
  294. var i = 0;
  295. var counter = function(){ i++; };
  296. var model = new Backbone.Model({a: 1});
  297. model.on('change:a', counter);
  298. model.set({a: 2});
  299. model.unset('a');
  300. model.unset('a');
  301. assert.equal(i, 2, 'Unset does not fire an event for missing attributes.');
  302. });
  303. QUnit.test('unset and changedAttributes', function(assert) {
  304. assert.expect(1);
  305. var model = new Backbone.Model({a: 1});
  306. model.on('change', function() {
  307. assert.ok('a' in model.changedAttributes(), 'changedAttributes should contain unset properties');
  308. });
  309. model.unset('a');
  310. });
  311. QUnit.test('using a non-default id attribute.', function(assert) {
  312. assert.expect(5);
  313. var MongoModel = Backbone.Model.extend({idAttribute: '_id'});
  314. var model = new MongoModel({id: 'eye-dee', _id: 25, title: 'Model'});
  315. assert.equal(model.get('id'), 'eye-dee');
  316. assert.equal(model.id, 25);
  317. assert.equal(model.isNew(), false);
  318. model.unset('_id');
  319. assert.equal(model.id, undefined);
  320. assert.equal(model.isNew(), true);
  321. });
  322. QUnit.test('setting an alternative cid prefix', function(assert) {
  323. assert.expect(4);
  324. var Model = Backbone.Model.extend({
  325. cidPrefix: 'm'
  326. });
  327. var model = new Model();
  328. assert.equal(model.cid.charAt(0), 'm');
  329. model = new Backbone.Model();
  330. assert.equal(model.cid.charAt(0), 'c');
  331. var Collection = Backbone.Collection.extend({
  332. model: Model
  333. });
  334. var col = new Collection([{id: 'c5'}, {id: 'c6'}, {id: 'c7'}]);
  335. assert.equal(col.get('c6').cid.charAt(0), 'm');
  336. col.set([{id: 'c6', value: 'test'}], {
  337. merge: true,
  338. add: true,
  339. remove: false
  340. });
  341. assert.ok(col.get('c6').has('value'));
  342. });
  343. QUnit.test('set an empty string', function(assert) {
  344. assert.expect(1);
  345. var model = new Backbone.Model({name: 'Model'});
  346. model.set({name: ''});
  347. assert.equal(model.get('name'), '');
  348. });
  349. QUnit.test('setting an object', function(assert) {
  350. assert.expect(1);
  351. var model = new Backbone.Model({
  352. custom: {foo: 1}
  353. });
  354. model.on('change', function() {
  355. assert.ok(1);
  356. });
  357. model.set({
  358. custom: {foo: 1} // no change should be fired
  359. });
  360. model.set({
  361. custom: {foo: 2} // change event should be fired
  362. });
  363. });
  364. QUnit.test('clear', function(assert) {
  365. assert.expect(3);
  366. var changed;
  367. var model = new Backbone.Model({id: 1, name: 'Model'});
  368. model.on('change:name', function(){ changed = true; });
  369. model.on('change', function() {
  370. var changedAttrs = model.changedAttributes();
  371. assert.ok('name' in changedAttrs);
  372. });
  373. model.clear();
  374. assert.equal(changed, true);
  375. assert.equal(model.get('name'), undefined);
  376. });
  377. QUnit.test('defaults', function(assert) {
  378. assert.expect(4);
  379. var Defaulted = Backbone.Model.extend({
  380. defaults: {
  381. one: 1,
  382. two: 2
  383. }
  384. });
  385. var model = new Defaulted({two: undefined});
  386. assert.equal(model.get('one'), 1);
  387. assert.equal(model.get('two'), 2);
  388. Defaulted = Backbone.Model.extend({
  389. defaults: function() {
  390. return {
  391. one: 3,
  392. two: 4
  393. };
  394. }
  395. });
  396. model = new Defaulted({two: undefined});
  397. assert.equal(model.get('one'), 3);
  398. assert.equal(model.get('two'), 4);
  399. });
  400. QUnit.test('change, hasChanged, changedAttributes, previous, previousAttributes', function(assert) {
  401. assert.expect(9);
  402. var model = new Backbone.Model({name: 'Tim', age: 10});
  403. assert.deepEqual(model.changedAttributes(), false);
  404. model.on('change', function() {
  405. assert.ok(model.hasChanged('name'), 'name changed');
  406. assert.ok(!model.hasChanged('age'), 'age did not');
  407. assert.ok(_.isEqual(model.changedAttributes(), {name: 'Rob'}), 'changedAttributes returns the changed attrs');
  408. assert.equal(model.previous('name'), 'Tim');
  409. assert.ok(_.isEqual(model.previousAttributes(), {name: 'Tim', age: 10}), 'previousAttributes is correct');
  410. });
  411. assert.equal(model.hasChanged(), false);
  412. assert.equal(model.hasChanged(undefined), false);
  413. model.set({name: 'Rob'});
  414. assert.equal(model.get('name'), 'Rob');
  415. });
  416. QUnit.test('changedAttributes', function(assert) {
  417. assert.expect(3);
  418. var model = new Backbone.Model({a: 'a', b: 'b'});
  419. assert.deepEqual(model.changedAttributes(), false);
  420. assert.equal(model.changedAttributes({a: 'a'}), false);
  421. assert.equal(model.changedAttributes({a: 'b'}).a, 'b');
  422. });
  423. QUnit.test('change with options', function(assert) {
  424. assert.expect(2);
  425. var value;
  426. var model = new Backbone.Model({name: 'Rob'});
  427. model.on('change', function(m, options) {
  428. value = options.prefix + m.get('name');
  429. });
  430. model.set({name: 'Bob'}, {prefix: 'Mr. '});
  431. assert.equal(value, 'Mr. Bob');
  432. model.set({name: 'Sue'}, {prefix: 'Ms. '});
  433. assert.equal(value, 'Ms. Sue');
  434. });
  435. QUnit.test('change after initialize', function(assert) {
  436. assert.expect(1);
  437. var changed = 0;
  438. var attrs = {id: 1, label: 'c'};
  439. var obj = new Backbone.Model(attrs);
  440. obj.on('change', function() { changed += 1; });
  441. obj.set(attrs);
  442. assert.equal(changed, 0);
  443. });
  444. QUnit.test('save within change event', function(assert) {
  445. assert.expect(1);
  446. var env = this;
  447. var model = new Backbone.Model({firstName: 'Taylor', lastName: 'Swift'});
  448. model.url = '/test';
  449. model.on('change', function() {
  450. model.save();
  451. assert.ok(_.isEqual(env.syncArgs.model, model));
  452. });
  453. model.set({lastName: 'Hicks'});
  454. });
  455. QUnit.test('validate after save', function(assert) {
  456. assert.expect(2);
  457. var lastError, model = new Backbone.Model();
  458. model.validate = function(attrs) {
  459. if (attrs.admin) return "Can't change admin status.";
  460. };
  461. model.sync = function(method, m, options) {
  462. options.success.call(this, {admin: true});
  463. };
  464. model.on('invalid', function(m, error) {
  465. lastError = error;
  466. });
  467. model.save(null);
  468. assert.equal(lastError, "Can't change admin status.");
  469. assert.equal(model.validationError, "Can't change admin status.");
  470. });
  471. QUnit.test('save', function(assert) {
  472. assert.expect(2);
  473. doc.save({title: 'Henry V'});
  474. assert.equal(this.syncArgs.method, 'update');
  475. assert.ok(_.isEqual(this.syncArgs.model, doc));
  476. });
  477. QUnit.test('save, fetch, destroy triggers error event when an error occurs', function(assert) {
  478. assert.expect(3);
  479. var model = new Backbone.Model();
  480. model.on('error', function() {
  481. assert.ok(true);
  482. });
  483. model.sync = function(method, m, options) {
  484. options.error();
  485. };
  486. model.save({data: 2, id: 1});
  487. model.fetch();
  488. model.destroy();
  489. });
  490. QUnit.test('#3283 - save, fetch, destroy calls success with context', function(assert) {
  491. assert.expect(3);
  492. var model = new Backbone.Model();
  493. var obj = {};
  494. var options = {
  495. context: obj,
  496. success: function() {
  497. assert.equal(this, obj);
  498. }
  499. };
  500. model.sync = function(method, m, opts) {
  501. opts.success.call(opts.context);
  502. };
  503. model.save({data: 2, id: 1}, options);
  504. model.fetch(options);
  505. model.destroy(options);
  506. });
  507. QUnit.test('#3283 - save, fetch, destroy calls error with context', function(assert) {
  508. assert.expect(3);
  509. var model = new Backbone.Model();
  510. var obj = {};
  511. var options = {
  512. context: obj,
  513. error: function() {
  514. assert.equal(this, obj);
  515. }
  516. };
  517. model.sync = function(method, m, opts) {
  518. opts.error.call(opts.context);
  519. };
  520. model.save({data: 2, id: 1}, options);
  521. model.fetch(options);
  522. model.destroy(options);
  523. });
  524. QUnit.test('#3470 - save and fetch with parse false', function(assert) {
  525. assert.expect(2);
  526. var i = 0;
  527. var model = new Backbone.Model();
  528. model.parse = function() {
  529. assert.ok(false);
  530. };
  531. model.sync = function(method, m, options) {
  532. options.success({i: ++i});
  533. };
  534. model.fetch({parse: false});
  535. assert.equal(model.get('i'), i);
  536. model.save(null, {parse: false});
  537. assert.equal(model.get('i'), i);
  538. });
  539. QUnit.test('save with PATCH', function(assert) {
  540. doc.clear().set({id: 1, a: 1, b: 2, c: 3, d: 4});
  541. doc.save();
  542. assert.equal(this.syncArgs.method, 'update');
  543. assert.equal(this.syncArgs.options.attrs, undefined);
  544. doc.save({b: 2, d: 4}, {patch: true});
  545. assert.equal(this.syncArgs.method, 'patch');
  546. assert.equal(_.size(this.syncArgs.options.attrs), 2);
  547. assert.equal(this.syncArgs.options.attrs.d, 4);
  548. assert.equal(this.syncArgs.options.attrs.a, undefined);
  549. assert.equal(this.ajaxSettings.data, '{"b":2,"d":4}');
  550. });
  551. QUnit.test('save with PATCH and different attrs', function(assert) {
  552. doc.clear().save({b: 2, d: 4}, {patch: true, attrs: {B: 1, D: 3}});
  553. assert.equal(this.syncArgs.options.attrs.D, 3);
  554. assert.equal(this.syncArgs.options.attrs.d, undefined);
  555. assert.equal(this.ajaxSettings.data, '{"B":1,"D":3}');
  556. assert.deepEqual(doc.attributes, {b: 2, d: 4});
  557. });
  558. QUnit.test('save in positional style', function(assert) {
  559. assert.expect(1);
  560. var model = new Backbone.Model();
  561. model.sync = function(method, m, options) {
  562. options.success();
  563. };
  564. model.save('title', 'Twelfth Night');
  565. assert.equal(model.get('title'), 'Twelfth Night');
  566. });
  567. QUnit.test('save with non-object success response', function(assert) {
  568. assert.expect(2);
  569. var model = new Backbone.Model();
  570. model.sync = function(method, m, options) {
  571. options.success('', options);
  572. options.success(null, options);
  573. };
  574. model.save({testing: 'empty'}, {
  575. success: function(m) {
  576. assert.deepEqual(m.attributes, {testing: 'empty'});
  577. }
  578. });
  579. });
  580. QUnit.test('save with wait and supplied id', function(assert) {
  581. var Model = Backbone.Model.extend({
  582. urlRoot: '/collection'
  583. });
  584. var model = new Model();
  585. model.save({id: 42}, {wait: true});
  586. assert.equal(this.ajaxSettings.url, '/collection/42');
  587. });
  588. QUnit.test('save will pass extra options to success callback', function(assert) {
  589. assert.expect(1);
  590. var SpecialSyncModel = Backbone.Model.extend({
  591. sync: function(method, m, options) {
  592. _.extend(options, {specialSync: true});
  593. return Backbone.Model.prototype.sync.call(this, method, m, options);
  594. },
  595. urlRoot: '/test'
  596. });
  597. var model = new SpecialSyncModel();
  598. var onSuccess = function(m, response, options) {
  599. assert.ok(options.specialSync, 'Options were passed correctly to callback');
  600. };
  601. model.save(null, {success: onSuccess});
  602. this.ajaxSettings.success();
  603. });
  604. QUnit.test('fetch', function(assert) {
  605. assert.expect(2);
  606. doc.fetch();
  607. assert.equal(this.syncArgs.method, 'read');
  608. assert.ok(_.isEqual(this.syncArgs.model, doc));
  609. });
  610. QUnit.test('fetch will pass extra options to success callback', function(assert) {
  611. assert.expect(1);
  612. var SpecialSyncModel = Backbone.Model.extend({
  613. sync: function(method, m, options) {
  614. _.extend(options, {specialSync: true});
  615. return Backbone.Model.prototype.sync.call(this, method, m, options);
  616. },
  617. urlRoot: '/test'
  618. });
  619. var model = new SpecialSyncModel();
  620. var onSuccess = function(m, response, options) {
  621. assert.ok(options.specialSync, 'Options were passed correctly to callback');
  622. };
  623. model.fetch({success: onSuccess});
  624. this.ajaxSettings.success();
  625. });
  626. QUnit.test('destroy', function(assert) {
  627. assert.expect(3);
  628. doc.destroy();
  629. assert.equal(this.syncArgs.method, 'delete');
  630. assert.ok(_.isEqual(this.syncArgs.model, doc));
  631. var newModel = new Backbone.Model;
  632. assert.equal(newModel.destroy(), false);
  633. });
  634. QUnit.test('destroy will pass extra options to success callback', function(assert) {
  635. assert.expect(1);
  636. var SpecialSyncModel = Backbone.Model.extend({
  637. sync: function(method, m, options) {
  638. _.extend(options, {specialSync: true});
  639. return Backbone.Model.prototype.sync.call(this, method, m, options);
  640. },
  641. urlRoot: '/test'
  642. });
  643. var model = new SpecialSyncModel({id: 'id'});
  644. var onSuccess = function(m, response, options) {
  645. assert.ok(options.specialSync, 'Options were passed correctly to callback');
  646. };
  647. model.destroy({success: onSuccess});
  648. this.ajaxSettings.success();
  649. });
  650. QUnit.test('non-persisted destroy', function(assert) {
  651. assert.expect(1);
  652. var a = new Backbone.Model({foo: 1, bar: 2, baz: 3});
  653. a.sync = function() { throw 'should not be called'; };
  654. a.destroy();
  655. assert.ok(true, 'non-persisted model should not call sync');
  656. });
  657. QUnit.test('validate', function(assert) {
  658. var lastError;
  659. var model = new Backbone.Model();
  660. model.validate = function(attrs) {
  661. if (attrs.admin !== this.get('admin')) return "Can't change admin status.";
  662. };
  663. model.on('invalid', function(m, error) {
  664. lastError = error;
  665. });
  666. var result = model.set({a: 100});
  667. assert.equal(result, model);
  668. assert.equal(model.get('a'), 100);
  669. assert.equal(lastError, undefined);
  670. result = model.set({admin: true});
  671. assert.equal(model.get('admin'), true);
  672. result = model.set({a: 200, admin: false}, {validate: true});
  673. assert.equal(lastError, "Can't change admin status.");
  674. assert.equal(result, false);
  675. assert.equal(model.get('a'), 100);
  676. });
  677. QUnit.test('validate on unset and clear', function(assert) {
  678. assert.expect(6);
  679. var error;
  680. var model = new Backbone.Model({name: 'One'});
  681. model.validate = function(attrs) {
  682. if (!attrs.name) {
  683. error = true;
  684. return 'No thanks.';
  685. }
  686. };
  687. model.set({name: 'Two'});
  688. assert.equal(model.get('name'), 'Two');
  689. assert.equal(error, undefined);
  690. model.unset('name', {validate: true});
  691. assert.equal(error, true);
  692. assert.equal(model.get('name'), 'Two');
  693. model.clear({validate: true});
  694. assert.equal(model.get('name'), 'Two');
  695. delete model.validate;
  696. model.clear();
  697. assert.equal(model.get('name'), undefined);
  698. });
  699. QUnit.test('validate with error callback', function(assert) {
  700. assert.expect(8);
  701. var lastError, boundError;
  702. var model = new Backbone.Model();
  703. model.validate = function(attrs) {
  704. if (attrs.admin) return "Can't change admin status.";
  705. };
  706. model.on('invalid', function(m, error) {
  707. boundError = true;
  708. });
  709. var result = model.set({a: 100}, {validate: true});
  710. assert.equal(result, model);
  711. assert.equal(model.get('a'), 100);
  712. assert.equal(model.validationError, null);
  713. assert.equal(boundError, undefined);
  714. result = model.set({a: 200, admin: true}, {validate: true});
  715. assert.equal(result, false);
  716. assert.equal(model.get('a'), 100);
  717. assert.equal(model.validationError, "Can't change admin status.");
  718. assert.equal(boundError, true);
  719. });
  720. QUnit.test('defaults always extend attrs (#459)', function(assert) {
  721. assert.expect(2);
  722. var Defaulted = Backbone.Model.extend({
  723. defaults: {one: 1},
  724. initialize: function(attrs, opts) {
  725. assert.equal(this.attributes.one, 1);
  726. }
  727. });
  728. var providedattrs = new Defaulted({});
  729. var emptyattrs = new Defaulted();
  730. });
  731. QUnit.test('Inherit class properties', function(assert) {
  732. assert.expect(6);
  733. var Parent = Backbone.Model.extend({
  734. instancePropSame: function() {},
  735. instancePropDiff: function() {}
  736. }, {
  737. classProp: function() {}
  738. });
  739. var Child = Parent.extend({
  740. instancePropDiff: function() {}
  741. });
  742. var adult = new Parent;
  743. var kid = new Child;
  744. assert.equal(Child.classProp, Parent.classProp);
  745. assert.notEqual(Child.classProp, undefined);
  746. assert.equal(kid.instancePropSame, adult.instancePropSame);
  747. assert.notEqual(kid.instancePropSame, undefined);
  748. assert.notEqual(Child.prototype.instancePropDiff, Parent.prototype.instancePropDiff);
  749. assert.notEqual(Child.prototype.instancePropDiff, undefined);
  750. });
  751. QUnit.test("Nested change events don't clobber previous attributes", function(assert) {
  752. assert.expect(4);
  753. new Backbone.Model()
  754. .on('change:state', function(m, newState) {
  755. assert.equal(m.previous('state'), undefined);
  756. assert.equal(newState, 'hello');
  757. // Fire a nested change event.
  758. m.set({other: 'whatever'});
  759. })
  760. .on('change:state', function(m, newState) {
  761. assert.equal(m.previous('state'), undefined);
  762. assert.equal(newState, 'hello');
  763. })
  764. .set({state: 'hello'});
  765. });
  766. QUnit.test('hasChanged/set should use same comparison', function(assert) {
  767. assert.expect(2);
  768. var changed = 0, model = new Backbone.Model({a: null});
  769. model.on('change', function() {
  770. assert.ok(this.hasChanged('a'));
  771. })
  772. .on('change:a', function() {
  773. changed++;
  774. })
  775. .set({a: undefined});
  776. assert.equal(changed, 1);
  777. });
  778. QUnit.test('#582, #425, change:attribute callbacks should fire after all changes have occurred', function(assert) {
  779. assert.expect(9);
  780. var model = new Backbone.Model;
  781. var assertion = function() {
  782. assert.equal(model.get('a'), 'a');
  783. assert.equal(model.get('b'), 'b');
  784. assert.equal(model.get('c'), 'c');
  785. };
  786. model.on('change:a', assertion);
  787. model.on('change:b', assertion);
  788. model.on('change:c', assertion);
  789. model.set({a: 'a', b: 'b', c: 'c'});
  790. });
  791. QUnit.test('#871, set with attributes property', function(assert) {
  792. assert.expect(1);
  793. var model = new Backbone.Model();
  794. model.set({attributes: true});
  795. assert.ok(model.has('attributes'));
  796. });
  797. QUnit.test('set value regardless of equality/change', function(assert) {
  798. assert.expect(1);
  799. var model = new Backbone.Model({x: []});
  800. var a = [];
  801. model.set({x: a});
  802. assert.ok(model.get('x') === a);
  803. });
  804. QUnit.test('set same value does not trigger change', function(assert) {
  805. assert.expect(0);
  806. var model = new Backbone.Model({x: 1});
  807. model.on('change change:x', function() { assert.ok(false); });
  808. model.set({x: 1});
  809. model.set({x: 1});
  810. });
  811. QUnit.test('unset does not fire a change for undefined attributes', function(assert) {
  812. assert.expect(0);
  813. var model = new Backbone.Model({x: undefined});
  814. model.on('change:x', function(){ assert.ok(false); });
  815. model.unset('x');
  816. });
  817. QUnit.test('set: undefined values', function(assert) {
  818. assert.expect(1);
  819. var model = new Backbone.Model({x: undefined});
  820. assert.ok('x' in model.attributes);
  821. });
  822. QUnit.test('hasChanged works outside of change events, and true within', function(assert) {
  823. assert.expect(6);
  824. var model = new Backbone.Model({x: 1});
  825. model.on('change:x', function() {
  826. assert.ok(model.hasChanged('x'));
  827. assert.equal(model.get('x'), 1);
  828. });
  829. model.set({x: 2}, {silent: true});
  830. assert.ok(model.hasChanged());
  831. assert.equal(model.hasChanged('x'), true);
  832. model.set({x: 1});
  833. assert.ok(model.hasChanged());
  834. assert.equal(model.hasChanged('x'), true);
  835. });
  836. QUnit.test('hasChanged gets cleared on the following set', function(assert) {
  837. assert.expect(4);
  838. var model = new Backbone.Model;
  839. model.set({x: 1});
  840. assert.ok(model.hasChanged());
  841. model.set({x: 1});
  842. assert.ok(!model.hasChanged());
  843. model.set({x: 2});
  844. assert.ok(model.hasChanged());
  845. model.set({});
  846. assert.ok(!model.hasChanged());
  847. });
  848. QUnit.test('save with `wait` succeeds without `validate`', function(assert) {
  849. assert.expect(1);
  850. var model = new Backbone.Model();
  851. model.url = '/test';
  852. model.save({x: 1}, {wait: true});
  853. assert.ok(this.syncArgs.model === model);
  854. });
  855. QUnit.test("save without `wait` doesn't set invalid attributes", function(assert) {
  856. var model = new Backbone.Model();
  857. model.validate = function() { return 1; };
  858. model.save({a: 1});
  859. assert.equal(model.get('a'), void 0);
  860. });
  861. QUnit.test("save doesn't validate twice", function(assert) {
  862. var model = new Backbone.Model();
  863. var times = 0;
  864. model.sync = function() {};
  865. model.validate = function() { ++times; };
  866. model.save({});
  867. assert.equal(times, 1);
  868. });
  869. QUnit.test('`hasChanged` for falsey keys', function(assert) {
  870. assert.expect(2);
  871. var model = new Backbone.Model();
  872. model.set({x: true}, {silent: true});
  873. assert.ok(!model.hasChanged(0));
  874. assert.ok(!model.hasChanged(''));
  875. });
  876. QUnit.test('`previous` for falsey keys', function(assert) {
  877. assert.expect(2);
  878. var model = new Backbone.Model({0: true, '': true});
  879. model.set({0: false, '': false}, {silent: true});
  880. assert.equal(model.previous(0), true);
  881. assert.equal(model.previous(''), true);
  882. });
  883. QUnit.test('`save` with `wait` sends correct attributes', function(assert) {
  884. assert.expect(5);
  885. var changed = 0;
  886. var model = new Backbone.Model({x: 1, y: 2});
  887. model.url = '/test';
  888. model.on('change:x', function() { changed++; });
  889. model.save({x: 3}, {wait: true});
  890. assert.deepEqual(JSON.parse(this.ajaxSettings.data), {x: 3, y: 2});
  891. assert.equal(model.get('x'), 1);
  892. assert.equal(changed, 0);
  893. this.syncArgs.options.success({});
  894. assert.equal(model.get('x'), 3);
  895. assert.equal(changed, 1);
  896. });
  897. QUnit.test("a failed `save` with `wait` doesn't leave attributes behind", function(assert) {
  898. assert.expect(1);
  899. var model = new Backbone.Model;
  900. model.url = '/test';
  901. model.save({x: 1}, {wait: true});
  902. assert.equal(model.get('x'), void 0);
  903. });
  904. QUnit.test('#1030 - `save` with `wait` results in correct attributes if success is called during sync', function(assert) {
  905. assert.expect(2);
  906. var model = new Backbone.Model({x: 1, y: 2});
  907. model.sync = function(method, m, options) {
  908. options.success();
  909. };
  910. model.on('change:x', function() { assert.ok(true); });
  911. model.save({x: 3}, {wait: true});
  912. assert.equal(model.get('x'), 3);
  913. });
  914. QUnit.test('save with wait validates attributes', function(assert) {
  915. var model = new Backbone.Model();
  916. model.url = '/test';
  917. model.validate = function() { assert.ok(true); };
  918. model.save({x: 1}, {wait: true});
  919. });
  920. QUnit.test('save turns on parse flag', function(assert) {
  921. var Model = Backbone.Model.extend({
  922. sync: function(method, m, options) { assert.ok(options.parse); }
  923. });
  924. new Model().save();
  925. });
  926. QUnit.test("nested `set` during `'change:attr'`", function(assert) {
  927. assert.expect(2);
  928. var events = [];
  929. var model = new Backbone.Model();
  930. model.on('all', function(event) { events.push(event); });
  931. model.on('change', function() {
  932. model.set({z: true}, {silent: true});
  933. });
  934. model.on('change:x', function() {
  935. model.set({y: true});
  936. });
  937. model.set({x: true});
  938. assert.deepEqual(events, ['change:y', 'change:x', 'change']);
  939. events = [];
  940. model.set({z: true});
  941. assert.deepEqual(events, []);
  942. });
  943. QUnit.test('nested `change` only fires once', function(assert) {
  944. assert.expect(1);
  945. var model = new Backbone.Model();
  946. model.on('change', function() {
  947. assert.ok(true);
  948. model.set({x: true});
  949. });
  950. model.set({x: true});
  951. });
  952. QUnit.test("nested `set` during `'change'`", function(assert) {
  953. assert.expect(6);
  954. var count = 0;
  955. var model = new Backbone.Model();
  956. model.on('change', function() {
  957. switch (count++) {
  958. case 0:
  959. assert.deepEqual(this.changedAttributes(), {x: true});
  960. assert.equal(model.previous('x'), undefined);
  961. model.set({y: true});
  962. break;
  963. case 1:
  964. assert.deepEqual(this.changedAttributes(), {x: true, y: true});
  965. assert.equal(model.previous('x'), undefined);
  966. model.set({z: true});
  967. break;
  968. case 2:
  969. assert.deepEqual(this.changedAttributes(), {x: true, y: true, z: true});
  970. assert.equal(model.previous('y'), undefined);
  971. break;
  972. default:
  973. assert.ok(false);
  974. }
  975. });
  976. model.set({x: true});
  977. });
  978. QUnit.test('nested `change` with silent', function(assert) {
  979. assert.expect(3);
  980. var count = 0;
  981. var model = new Backbone.Model();
  982. model.on('change:y', function() { assert.ok(false); });
  983. model.on('change', function() {
  984. switch (count++) {
  985. case 0:
  986. assert.deepEqual(this.changedAttributes(), {x: true});
  987. model.set({y: true}, {silent: true});
  988. model.set({z: true});
  989. break;
  990. case 1:
  991. assert.deepEqual(this.changedAttributes(), {x: true, y: true, z: true});
  992. break;
  993. case 2:
  994. assert.deepEqual(this.changedAttributes(), {z: false});
  995. break;
  996. default:
  997. assert.ok(false);
  998. }
  999. });
  1000. model.set({x: true});
  1001. model.set({z: false});
  1002. });
  1003. QUnit.test('nested `change:attr` with silent', function(assert) {
  1004. assert.expect(0);
  1005. var model = new Backbone.Model();
  1006. model.on('change:y', function(){ assert.ok(false); });
  1007. model.on('change', function() {
  1008. model.set({y: true}, {silent: true});
  1009. model.set({z: true});
  1010. });
  1011. model.set({x: true});
  1012. });
  1013. QUnit.test('multiple nested changes with silent', function(assert) {
  1014. assert.expect(1);
  1015. var model = new Backbone.Model();
  1016. model.on('change:x', function() {
  1017. model.set({y: 1}, {silent: true});
  1018. model.set({y: 2});
  1019. });
  1020. model.on('change:y', function(m, val) {
  1021. assert.equal(val, 2);
  1022. });
  1023. model.set({x: true});
  1024. });
  1025. QUnit.test('multiple nested changes with silent', function(assert) {
  1026. assert.expect(1);
  1027. var changes = [];
  1028. var model = new Backbone.Model();
  1029. model.on('change:b', function(m, val) { changes.push(val); });
  1030. model.on('change', function() {
  1031. model.set({b: 1});
  1032. });
  1033. model.set({b: 0});
  1034. assert.deepEqual(changes, [0, 1]);
  1035. });
  1036. QUnit.test('basic silent change semantics', function(assert) {
  1037. assert.expect(1);
  1038. var model = new Backbone.Model;
  1039. model.set({x: 1});
  1040. model.on('change', function(){ assert.ok(true); });
  1041. model.set({x: 2}, {silent: true});
  1042. model.set({x: 1});
  1043. });
  1044. QUnit.test('nested set multiple times', function(assert) {
  1045. assert.expect(1);
  1046. var model = new Backbone.Model();
  1047. model.on('change:b', function() {
  1048. assert.ok(true);
  1049. });
  1050. model.on('change:a', function() {
  1051. model.set({b: true});
  1052. model.set({b: true});
  1053. });
  1054. model.set({a: true});
  1055. });
  1056. QUnit.test('#1122 - clear does not alter options.', function(assert) {
  1057. assert.expect(1);
  1058. var model = new Backbone.Model();
  1059. var options = {};
  1060. model.clear(options);
  1061. assert.ok(!options.unset);
  1062. });
  1063. QUnit.test('#1122 - unset does not alter options.', function(assert) {
  1064. assert.expect(1);
  1065. var model = new Backbone.Model();
  1066. var options = {};
  1067. model.unset('x', options);
  1068. assert.ok(!options.unset);
  1069. });
  1070. QUnit.test('#1355 - `options` is passed to success callbacks', function(assert) {
  1071. assert.expect(3);
  1072. var model = new Backbone.Model();
  1073. var opts = {
  1074. success: function( m, resp, options ) {
  1075. assert.ok(options);
  1076. }
  1077. };
  1078. model.sync = function(method, m, options) {
  1079. options.success();
  1080. };
  1081. model.save({id: 1}, opts);
  1082. model.fetch(opts);
  1083. model.destroy(opts);
  1084. });
  1085. QUnit.test("#1412 - Trigger 'sync' event.", function(assert) {
  1086. assert.expect(3);
  1087. var model = new Backbone.Model({id: 1});
  1088. model.sync = function(method, m, options) { options.success(); };
  1089. model.on('sync', function(){ assert.ok(true); });
  1090. model.fetch();
  1091. model.save();
  1092. model.destroy();
  1093. });
  1094. QUnit.test('#1365 - Destroy: New models execute success callback.', function(assert) {
  1095. var done = assert.async();
  1096. assert.expect(2);
  1097. new Backbone.Model()
  1098. .on('sync', function() { assert.ok(false); })
  1099. .on('destroy', function(){ assert.ok(true); })
  1100. .destroy({success: function(){
  1101. assert.ok(true);
  1102. done();
  1103. }});
  1104. });
  1105. QUnit.test('#1433 - Save: An invalid model cannot be persisted.', function(assert) {
  1106. assert.expect(1);
  1107. var model = new Backbone.Model;
  1108. model.validate = function(){ return 'invalid'; };
  1109. model.sync = function(){ assert.ok(false); };
  1110. assert.strictEqual(model.save(), false);
  1111. });
  1112. QUnit.test("#1377 - Save without attrs triggers 'error'.", function(assert) {
  1113. assert.expect(1);
  1114. var Model = Backbone.Model.extend({
  1115. url: '/test/',
  1116. sync: function(method, m, options){ options.success(); },
  1117. validate: function(){ return 'invalid'; }
  1118. });
  1119. var model = new Model({id: 1});
  1120. model.on('invalid', function(){ assert.ok(true); });
  1121. model.save();
  1122. });
  1123. QUnit.test('#1545 - `undefined` can be passed to a model constructor without coersion', function(assert) {
  1124. var Model = Backbone.Model.extend({
  1125. defaults: {one: 1},
  1126. initialize: function(attrs, opts) {
  1127. assert.equal(attrs, undefined);
  1128. }
  1129. });
  1130. var emptyattrs = new Model();
  1131. var undefinedattrs = new Model(undefined);
  1132. });
  1133. QUnit.test('#1478 - Model `save` does not trigger change on unchanged attributes', function(assert) {
  1134. var done = assert.async();
  1135. assert.expect(0);
  1136. var Model = Backbone.Model.extend({
  1137. sync: function(method, m, options) {
  1138. setTimeout(function(){
  1139. options.success();
  1140. done();
  1141. }, 0);
  1142. }
  1143. });
  1144. new Model({x: true})
  1145. .on('change:x', function(){ assert.ok(false); })
  1146. .save(null, {wait: true});
  1147. });
  1148. QUnit.test('#1664 - Changing from one value, silently to another, back to original triggers a change.', function(assert) {
  1149. assert.expect(1);
  1150. var model = new Backbone.Model({x: 1});
  1151. model.on('change:x', function() { assert.ok(true); });
  1152. model.set({x: 2}, {silent: true});
  1153. model.set({x: 3}, {silent: true});
  1154. model.set({x: 1});
  1155. });
  1156. QUnit.test('#1664 - multiple silent changes nested inside a change event', function(assert) {
  1157. assert.expect(2);
  1158. var changes = [];
  1159. var model = new Backbone.Model();
  1160. model.on('change', function() {
  1161. model.set({a: 'c'}, {silent: true});
  1162. model.set({b: 2}, {silent: true});
  1163. model.unset('c', {silent: true});
  1164. });
  1165. model.on('change:a change:b change:c', function(m, val) { changes.push(val); });
  1166. model.set({a: 'a', b: 1, c: 'item'});
  1167. assert.deepEqual(changes, ['a', 1, 'item']);
  1168. assert.deepEqual(model.attributes, {a: 'c', b: 2});
  1169. });
  1170. QUnit.test('#1791 - `attributes` is available for `parse`', function(assert) {
  1171. var Model = Backbone.Model.extend({
  1172. parse: function() { this.has('a'); } // shouldn't throw an error
  1173. });
  1174. var model = new Model(null, {parse: true});
  1175. assert.expect(0);
  1176. });
  1177. QUnit.test('silent changes in last `change` event back to original triggers change', function(assert) {
  1178. assert.expect(2);
  1179. var changes = [];
  1180. var model = new Backbone.Model();
  1181. model.on('change:a change:b change:c', function(m, val) { changes.push(val); });
  1182. model.on('change', function() {
  1183. model.set({a: 'c'}, {silent: true});
  1184. });
  1185. model.set({a: 'a'});
  1186. assert.deepEqual(changes, ['a']);
  1187. model.set({a: 'a'});
  1188. assert.deepEqual(changes, ['a', 'a']);
  1189. });
  1190. QUnit.test('#1943 change calculations should use _.isEqual', function(assert) {
  1191. var model = new Backbone.Model({a: {key: 'value'}});
  1192. model.set('a', {key: 'value'}, {silent: true});
  1193. assert.equal(model.changedAttributes(), false);
  1194. });
  1195. QUnit.test('#1964 - final `change` event is always fired, regardless of interim changes', function(assert) {
  1196. assert.expect(1);
  1197. var model = new Backbone.Model();
  1198. model.on('change:property', function() {
  1199. model.set('property', 'bar');
  1200. });
  1201. model.on('change', function() {
  1202. assert.ok(true);
  1203. });
  1204. model.set('property', 'foo');
  1205. });
  1206. QUnit.test('isValid', function(assert) {
  1207. var model = new Backbone.Model({valid: true});
  1208. model.validate = function(attrs) {
  1209. if (!attrs.valid) return 'invalid';
  1210. };
  1211. assert.equal(model.isValid(), true);
  1212. assert.equal(model.set({valid: false}, {validate: true}), false);
  1213. assert.equal(model.isValid(), true);
  1214. model.set({valid: false});
  1215. assert.equal(model.isValid(), false);
  1216. assert.ok(!model.set('valid', false, {validate: true}));
  1217. });
  1218. QUnit.test('#1179 - isValid returns true in the absence of validate.', function(assert) {
  1219. assert.expect(1);
  1220. var model = new Backbone.Model();
  1221. model.validate = null;
  1222. assert.ok(model.isValid());
  1223. });
  1224. QUnit.test('#1961 - Creating a model with {validate:true} will call validate and use the error callback', function(assert) {
  1225. var Model = Backbone.Model.extend({
  1226. validate: function(attrs) {
  1227. if (attrs.id === 1) return "This shouldn't happen";
  1228. }
  1229. });
  1230. var model = new Model({id: 1}, {validate: true});
  1231. assert.equal(model.validationError, "This shouldn't happen");
  1232. });
  1233. QUnit.test('toJSON receives attrs during save(..., {wait: true})', function(assert) {
  1234. assert.expect(1);
  1235. var Model = Backbone.Model.extend({
  1236. url: '/test',
  1237. toJSON: function() {
  1238. assert.strictEqual(this.attributes.x, 1);
  1239. return _.clone(this.attributes);
  1240. }
  1241. });
  1242. var model = new Model;
  1243. model.save({x: 1}, {wait: true});
  1244. });
  1245. QUnit.test('#2034 - nested set with silent only triggers one change', function(assert) {
  1246. assert.expect(1);
  1247. var model = new Backbone.Model();
  1248. model.on('change', function() {
  1249. model.set({b: true}, {silent: true});
  1250. assert.ok(true);
  1251. });
  1252. model.set({a: true});
  1253. });
  1254. QUnit.test('#3778 - id will only be updated if it is set', function(assert) {
  1255. assert.expect(2);
  1256. var model = new Backbone.Model({id: 1});
  1257. model.id = 2;
  1258. model.set({foo: 'bar'});
  1259. assert.equal(model.id, 2);
  1260. model.set({id: 3});
  1261. assert.equal(model.id, 3);
  1262. });
  1263. })();