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