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
|
|
|
})(); |
1419
|
|
|
|