PageRenderTime 32ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/www/lib/lodash/vendor/backbone/test/model.js

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