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