~ubuntu-branches/ubuntu/precise/whoopsie-daisy/precise-updates

« back to all changes in this revision

Viewing changes to backend/stats/static/js/yui/3.4.1/tests/app/tests/app-test.js

  • Committer: Package Import Robot
  • Author(s): Evan Dandrea
  • Date: 2012-04-18 13:04:36 UTC
  • Revision ID: package-import@ubuntu.com-20120418130436-vmt93p8fds516lws
Tags: 0.1.32
Fix failing tests on powerpc and ARM.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
YUI.add('app-test', function (Y) {
2
 
 
3
 
var ArrayAssert  = Y.ArrayAssert,
4
 
    Assert       = Y.Assert,
5
 
    ObjectAssert = Y.ObjectAssert,
6
 
 
7
 
    html5 = Y.Controller.prototype.html5,
8
 
 
9
 
    controllerSuite,
10
 
    modelSuite,
11
 
    modelListSuite,
12
 
    suite,
13
 
    viewSuite;
14
 
 
15
 
// -- Global Suite -------------------------------------------------------------
16
 
suite = new Y.Test.Suite('App Framework');
17
 
 
18
 
// -- Controller Suite ---------------------------------------------------------
19
 
controllerSuite = new Y.Test.Suite({
20
 
    name: 'Controller',
21
 
 
22
 
    setUp: function () {
23
 
        this.oldPath = Y.config.win.location.toString();
24
 
 
25
 
        if (!html5) {
26
 
            Y.config.win.location.hash = '';
27
 
        }
28
 
    },
29
 
 
30
 
    tearDown: function () {
31
 
        if (html5) {
32
 
            Y.config.win.history.replaceState(null, null, this.oldPath);
33
 
        } else {
34
 
            Y.config.win.location.hash = '';
35
 
        }
36
 
    }
37
 
});
38
 
 
39
 
// -- Controller: Lifecycle ----------------------------------------------------
40
 
controllerSuite.add(new Y.Test.Case({
41
 
    name: 'Lifecycle',
42
 
 
43
 
    tearDown: function () {
44
 
        this.controller && this.controller.destroy();
45
 
        delete this.controller;
46
 
    },
47
 
 
48
 
    'initializer should set local `root` and `routes` properties': function () {
49
 
        var controller = this.controller = new Y.Controller({
50
 
                root: '/foo',
51
 
 
52
 
                routes: [
53
 
                    {path: '/', callback: function () {}},
54
 
                    {path: '/foo', callback: function () {}}
55
 
                ]
56
 
            });
57
 
 
58
 
        Assert.areSame('/foo', controller.root);
59
 
        Assert.areSame(2, controller.routes.length);
60
 
        Assert.areSame('/', controller.routes[0].path);
61
 
        Assert.areSame('/foo', controller.routes[1].path);
62
 
    },
63
 
 
64
 
    'initializer should create initial routes': function () {
65
 
        var controller = this.controller = new Y.Controller({
66
 
                routes: [
67
 
                    {path: '/', callback: function () {}},
68
 
                    {path: '/foo', callback: function () {}}
69
 
                ]
70
 
            });
71
 
 
72
 
        Assert.areSame(2, controller._routes.length);
73
 
        Assert.areSame(controller.routes[0].callback, controller._routes[0].callback);
74
 
        Assert.areSame(controller.routes[1].callback, controller._routes[1].callback);
75
 
    }
76
 
}));
77
 
 
78
 
// -- Controller: Events -------------------------------------------------------
79
 
controllerSuite.add(new Y.Test.Case({
80
 
    name: 'Events',
81
 
 
82
 
    tearDown: function () {
83
 
        this.controller && this.controller.destroy();
84
 
        delete this.controller;
85
 
    },
86
 
 
87
 
    '`ready` event should fire when the controller is ready to dispatch': function () {
88
 
        var test = this,
89
 
 
90
 
            controller = this.controller = new Y.Controller({
91
 
                on: {
92
 
                    ready: function (e) {
93
 
                        test.resume(function () {
94
 
                            Assert.isFalse(e.dispatched);
95
 
                        });
96
 
                    }
97
 
                }
98
 
            });
99
 
 
100
 
        this.wait(1000);
101
 
    },
102
 
 
103
 
    '`ready` event should set e.dispatched to true if called after dispatch': function () {
104
 
        var test = this,
105
 
 
106
 
            controller = this.controller = new Y.Controller({
107
 
                on: {
108
 
                    initializedChange: function () {
109
 
                        this._dispatch('/fake', {});
110
 
                    },
111
 
 
112
 
                    ready: function (e) {
113
 
                        test.resume(function () {
114
 
                            Assert.isTrue(e.dispatched);
115
 
                        });
116
 
                    }
117
 
                }
118
 
            });
119
 
 
120
 
        this.wait(1000);
121
 
    }
122
 
}));
123
 
 
124
 
// -- Controller: Attributes and Properties ------------------------------------
125
 
controllerSuite.add(new Y.Test.Case({
126
 
    name: 'Attributes and Properties',
127
 
 
128
 
    tearDown: function () {
129
 
        this.controller && this.controller.destroy();
130
 
        delete this.controller;
131
 
    },
132
 
 
133
 
    '`root` property should have a default value': function () {
134
 
        var controller = this.controller = new Y.Controller();
135
 
        Assert.areSame('', controller.root);
136
 
    },
137
 
 
138
 
    '`routes` property should have a default value': function () {
139
 
        var controller = this.controller = new Y.Controller();
140
 
 
141
 
        Assert.isArray(controller.routes);
142
 
        ArrayAssert.isEmpty(controller.routes);
143
 
    }
144
 
}));
145
 
 
146
 
// -- Controller: Methods ------------------------------------------------------
147
 
controllerSuite.add(new Y.Test.Case({
148
 
    name: 'Methods',
149
 
 
150
 
    tearDown: function () {
151
 
        this.controller && this.controller.destroy();
152
 
        delete this.controller;
153
 
    },
154
 
 
155
 
    'route() should add a route': function () {
156
 
        var controller = this.controller = new Y.Controller();
157
 
 
158
 
        controller.one = function () {};
159
 
        function two() {}
160
 
 
161
 
        Assert.areSame(0, controller._routes.length);
162
 
 
163
 
        Assert.areSame(controller, controller.route('/foo', 'one'));
164
 
        Assert.areSame(1, controller._routes.length);
165
 
 
166
 
        controller.route(/bar/, two);
167
 
        Assert.areSame(2, controller._routes.length);
168
 
 
169
 
        Assert.areSame('one', controller._routes[0].callback);
170
 
        Assert.areSame(two, controller._routes[1].callback);
171
 
    },
172
 
 
173
 
    'match() should return an array of routes that match the given path': function () {
174
 
        var controller = this.controller = new Y.Controller(),
175
 
            routes;
176
 
 
177
 
        function one () {}
178
 
        function two() {}
179
 
        function three() {}
180
 
 
181
 
        controller.route('/:foo', one);
182
 
        controller.route(/foo/, two);
183
 
        controller.route('/bar', three);
184
 
 
185
 
        routes = controller.match('/foo');
186
 
 
187
 
        Assert.areSame(2, routes.length);
188
 
        Assert.areSame(one, routes[0].callback);
189
 
        Assert.areSame(two, routes[1].callback);
190
 
    },
191
 
 
192
 
    'hasRoute() should return `true` if one or more routes match the given path': function () {
193
 
        var controller = this.controller = new Y.Controller(),
194
 
            routes;
195
 
 
196
 
        function noop () {}
197
 
 
198
 
        controller.route('/:foo', noop);
199
 
        controller.route(/foo/, noop);
200
 
        controller.route('/bar', noop);
201
 
 
202
 
        Assert.isTrue(controller.hasRoute('/foo'));
203
 
        Assert.isTrue(controller.hasRoute('/bar'));
204
 
        Assert.isFalse(controller.hasRoute('/baz/quux'));
205
 
    },
206
 
 
207
 
    'dispatch() should dispatch to the first route that matches the current URL': function () {
208
 
        var test       = this,
209
 
            controller = this.controller = new Y.Controller();
210
 
 
211
 
        controller.route(/./, function () {
212
 
            test.resume();
213
 
        });
214
 
 
215
 
        setTimeout(function () {
216
 
            controller.dispatch();
217
 
        }, 1);
218
 
 
219
 
        this.wait(1000);
220
 
    },
221
 
 
222
 
    'dispatch() should upgrade hash URLs to HTML5 URLs in HTML5 browsers': function () {
223
 
        if (!html5) {
224
 
            Assert.isTrue(true);
225
 
            return;
226
 
        }
227
 
 
228
 
        Y.HistoryHash.setHash('/hashpath');
229
 
 
230
 
        var test       = this,
231
 
            controller = this.controller = new Y.Controller();
232
 
 
233
 
        controller.route('/hashpath', function (req) {
234
 
            test.resume(function () {
235
 
                Assert.areSame('/hashpath', req.path);
236
 
                Assert.areSame(Y.config.win.location.pathname, '/hashpath');
237
 
            });
238
 
        });
239
 
 
240
 
        controller.dispatch();
241
 
        this.wait(500);
242
 
    },
243
 
 
244
 
    'removeRoot() should remove the root URL from a given path': function () {
245
 
        var controller = this.controller = new Y.Controller();
246
 
 
247
 
        controller.root = '/';
248
 
        Assert.areSame('/bar', controller.removeRoot('/bar'));
249
 
        Assert.areSame('/bar', controller.removeRoot('bar'));
250
 
 
251
 
        controller.root = '/foo';
252
 
        Assert.areSame('/bar', controller.removeRoot('/foo/bar'));
253
 
 
254
 
        controller.root = '/foo/';
255
 
        Assert.areSame('/bar', controller.removeRoot('/foo/bar'));
256
 
 
257
 
        controller.root = '/moo';
258
 
        Assert.areSame('/foo/bar', controller.removeRoot('/foo/bar'));
259
 
    },
260
 
 
261
 
    'removeRoot() should strip the "http://foo.com" portion of the URL, if any': function () {
262
 
        var controller = this.controller = new Y.Controller();
263
 
 
264
 
        Assert.areSame('/foo/bar', controller.removeRoot('http://example.com/foo/bar'));
265
 
        Assert.areSame('/foo/bar', controller.removeRoot('https://example.com/foo/bar'));
266
 
        Assert.areSame('/foo/bar', controller.removeRoot('http://user:pass@example.com/foo/bar'));
267
 
        Assert.areSame('/foo/bar', controller.removeRoot('http://example.com:8080/foo/bar'));
268
 
        Assert.areSame('/foo/bar', controller.removeRoot('http://user:pass@example.com:8080/foo/bar'));
269
 
 
270
 
        controller.root = '/foo';
271
 
        Assert.areSame('/bar', controller.removeRoot('http://example.com/foo/bar'));
272
 
        Assert.areSame('/bar', controller.removeRoot('https://example.com/foo/bar'));
273
 
        Assert.areSame('/bar', controller.removeRoot('http://user:pass@example.com/foo/bar'));
274
 
        Assert.areSame('/bar', controller.removeRoot('http://example.com:8080/foo/bar'));
275
 
        Assert.areSame('/bar', controller.removeRoot('http://user:pass@example.com:8080/foo/bar'));
276
 
    },
277
 
 
278
 
    'replace() should replace the current history entry': function () {
279
 
        var test       = this,
280
 
            controller = this.controller = new Y.Controller();
281
 
 
282
 
        controller.route('/replace', function (req) {
283
 
            test.resume(function () {
284
 
                Assert.areSame('/replace', req.path);
285
 
                Assert.isObject(req.query);
286
 
            });
287
 
        });
288
 
 
289
 
        // Wrapped in a setTimeout to make the async test work on iOS<5, which
290
 
        // performs this action synchronously.
291
 
        setTimeout(function () {
292
 
            controller.replace('/replace');
293
 
        }, 1);
294
 
 
295
 
        this.wait(1000);
296
 
    },
297
 
 
298
 
    'save() should create a new history entry': function () {
299
 
        var test       = this,
300
 
            controller = this.controller = new Y.Controller();
301
 
 
302
 
        controller.route('/save', function (req) {
303
 
            test.resume(function () {
304
 
                Assert.areSame('/save', req.path);
305
 
                Assert.isObject(req.query);
306
 
            });
307
 
        });
308
 
 
309
 
        // Wrapped in a setTimeout to make the async test work on iOS<5, which
310
 
        // performs this action synchronously.
311
 
        setTimeout(function () {
312
 
            controller.save('/save');
313
 
        }, 1);
314
 
 
315
 
        this.wait(1000);
316
 
    },
317
 
 
318
 
    'consecutive save() calls should dispatch to the correct routes': function () {
319
 
        var paths      = [],
320
 
            test       = this,
321
 
            controller = this.controller = new Y.Controller();
322
 
 
323
 
        controller.route('/one', function (req) {
324
 
            paths.push(req.path);
325
 
        });
326
 
 
327
 
        controller.route('/two', function (req) {
328
 
            paths.push(req.path);
329
 
        });
330
 
 
331
 
        controller.route('/three', function (req) {
332
 
            paths.push(req.path);
333
 
 
334
 
            test.resume(function () {
335
 
                ArrayAssert.itemsAreSame(['/one', '/two', '/three'], paths);
336
 
            });
337
 
        });
338
 
 
339
 
        // Wrapped in a setTimeout to make the async test work on iOS<5, which
340
 
        // performs this action synchronously.
341
 
        setTimeout(function () {
342
 
            controller.save('/one');
343
 
            controller.save('/two');
344
 
            controller.save('/three');
345
 
        }, 1);
346
 
 
347
 
        this.wait(2000);
348
 
    },
349
 
 
350
 
    '_joinURL() should normalize / separators': function () {
351
 
        var controller = this.controller = new Y.Controller();
352
 
 
353
 
        controller.root = '/foo';
354
 
        Assert.areSame('/foo/bar', controller._joinURL('bar'));
355
 
        Assert.areSame('/foo/bar', controller._joinURL('/bar'));
356
 
 
357
 
        controller.root = '/foo/';
358
 
        Assert.areSame('/foo/bar', controller._joinURL('bar'));
359
 
        Assert.areSame('/foo/bar', controller._joinURL('/bar'));
360
 
    }
361
 
}));
362
 
 
363
 
// -- Controller: Routes -------------------------------------------------------
364
 
controllerSuite.add(new Y.Test.Case({
365
 
    name: 'Routes',
366
 
 
367
 
    tearDown: function () {
368
 
        this.controller && this.controller.destroy();
369
 
        delete this.controller;
370
 
    },
371
 
 
372
 
    'routes should be called in the context of the controller': function () {
373
 
        var calls      = 0,
374
 
            controller = this.controller = new Y.Controller({
375
 
                routes: [{path: '/foo', callback: 'foo'}]
376
 
            });
377
 
 
378
 
        controller.foo = function () {
379
 
            calls += 1;
380
 
            Assert.areSame(controller, this);
381
 
        };
382
 
 
383
 
        controller.route('/bar', controller.foo);
384
 
 
385
 
        controller._dispatch('/foo', {});
386
 
        controller._dispatch('/bar', {});
387
 
 
388
 
        Assert.areSame(2, calls);
389
 
    },
390
 
 
391
 
    'routes should receive a request object and `next` function as params': function () {
392
 
        var calls      = 0,
393
 
            controller = this.controller = new Y.Controller();
394
 
 
395
 
        controller.route('/foo', function (req, next) {
396
 
            calls += 1;
397
 
 
398
 
            Assert.isObject(req);
399
 
            Assert.isFunction(next);
400
 
            Assert.areSame(next, req.next);
401
 
            Assert.isObject(req.params);
402
 
            Assert.isTrue(Y.Object.isEmpty(req.params));
403
 
            Assert.areSame('/foo', req.path);
404
 
            ObjectAssert.areEqual({bar: 'baz quux', moo: ''}, req.query);
405
 
        });
406
 
 
407
 
        // Duckpunching _getQuery so we can test req.query.
408
 
        controller._getQuery = function () {
409
 
            return 'bar=baz%20quux&moo';
410
 
        };
411
 
 
412
 
        controller._dispatch('/foo', {foo: 'foo'});
413
 
 
414
 
        Assert.areSame(1, calls);
415
 
    },
416
 
 
417
 
    'request object should contain captured route parameters': function () {
418
 
        var calls      = 0,
419
 
            controller = this.controller = new Y.Controller();
420
 
 
421
 
        controller.route('/foo/:bar/:baz', function (req) {
422
 
            calls += 1;
423
 
 
424
 
            ArrayAssert.itemsAreSame(['bar', 'baz'], Y.Object.keys(req.params));
425
 
            ArrayAssert.itemsAreSame(['one', 'two'], Y.Object.values(req.params));
426
 
        });
427
 
 
428
 
        controller.route('/bar/*path', function (req) {
429
 
            calls += 1;
430
 
 
431
 
            Assert.isObject(req.params);
432
 
            ArrayAssert.itemsAreSame(['path'], Y.Object.keys(req.params));
433
 
            ArrayAssert.itemsAreSame(['one/two'], Y.Object.values(req.params));
434
 
        });
435
 
 
436
 
        controller.route(/^\/(baz)\/(quux)$/, function (req) {
437
 
            calls += 1;
438
 
 
439
 
            Assert.isArray(req.params);
440
 
            ArrayAssert.itemsAreSame(['/baz/quux', 'baz', 'quux'], req.params);
441
 
        });
442
 
 
443
 
        controller._dispatch('/foo/one/two', {});
444
 
        controller._dispatch('/bar/one/two', {});
445
 
        controller._dispatch('/baz/quux', {});
446
 
 
447
 
        Assert.areSame(3, calls);
448
 
    },
449
 
 
450
 
    'calling `next()` should pass control to the next matching route': function () {
451
 
        var calls      = 0,
452
 
            controller = this.controller = new Y.Controller();
453
 
 
454
 
        controller.route('/foo', function (req, next) {
455
 
            calls += 1;
456
 
            next();
457
 
        });
458
 
 
459
 
        controller.route(/foo/, function (req, next) {
460
 
            calls += 1;
461
 
            next();
462
 
        });
463
 
 
464
 
        controller.route('/foo', function (req, next) {
465
 
            calls += 1;
466
 
        });
467
 
 
468
 
        controller.route('/foo', function (req, next) {
469
 
            calls += 1;
470
 
            Assert.fail('final route should not be called');
471
 
        });
472
 
 
473
 
        controller._dispatch('/foo', {});
474
 
 
475
 
        Assert.areSame(3, calls);
476
 
    }
477
 
}));
478
 
 
479
 
// -- Model Suite --------------------------------------------------------------
480
 
modelSuite = new Y.Test.Suite('Model');
481
 
 
482
 
// -- Model: Lifecycle ---------------------------------------------------------
483
 
modelSuite.add(new Y.Test.Case({
484
 
    name: 'Lifecycle',
485
 
 
486
 
    'destroy() should destroy the model instance': function () {
487
 
        var model = new Y.Model();
488
 
 
489
 
        model.sync = function () {
490
 
            Assert.fail('sync should not be called unless the model is being deleted');
491
 
        };
492
 
 
493
 
        Assert.isFalse(model.get('destroyed'));
494
 
        Assert.areSame(model, model.destroy(), 'destroy() should be chainable');
495
 
        Assert.isTrue(model.get('destroyed'));
496
 
    },
497
 
 
498
 
    'destroy() should call a callback if provided as the only arg': function () {
499
 
        var mock  = Y.Mock(),
500
 
            model = new Y.Model();
501
 
 
502
 
        Y.Mock.expect(mock, {
503
 
            method: 'callback',
504
 
            args  : []
505
 
        });
506
 
 
507
 
        model.destroy(mock.callback);
508
 
        Y.Mock.verify(mock);
509
 
    },
510
 
 
511
 
    'destroy() should call a callback if provided as the second arg': function () {
512
 
        var mock  = Y.Mock(),
513
 
            model = new Y.Model();
514
 
 
515
 
        Y.Mock.expect(mock, {
516
 
            method: 'callback',
517
 
            args  : []
518
 
        });
519
 
 
520
 
        model.destroy({}, mock.callback);
521
 
        Y.Mock.verify(mock);
522
 
    },
523
 
 
524
 
    'destroy() should delete the model if the `delete` option is truthy': function () {
525
 
        var calls   = 0,
526
 
            mock    = Y.Mock(),
527
 
            model   = new Y.Model();
528
 
 
529
 
        Y.Mock.expect(mock, {
530
 
            method: 'callback',
531
 
            args  : []
532
 
        });
533
 
 
534
 
        model.sync = function (action, options, callback) {
535
 
            calls += 1;
536
 
 
537
 
            Assert.areSame('delete', action, 'sync action should be "delete"');
538
 
            Assert.isObject(options, 'options should be an object');
539
 
            Assert.isTrue(options['delete'], 'options.delete should be true');
540
 
            Assert.isFunction(callback, 'callback should be a function');
541
 
 
542
 
            callback();
543
 
        };
544
 
 
545
 
        model.destroy({'delete': true}, mock.callback);
546
 
        Y.Mock.verify(mock);
547
 
    },
548
 
 
549
 
    'destroy() should remove the model from all lists': function () {
550
 
        var model     = new Y.Model(),
551
 
            listOne   = new Y.ModelList(),
552
 
            listTwo   = new Y.ModelList(),
553
 
            listThree = new Y.ModelList();
554
 
 
555
 
        listOne.add(model);
556
 
        listTwo.add(model);
557
 
        listThree.add(model);
558
 
 
559
 
        Assert.areSame(1, listOne.size(), 'model should be added to list one');
560
 
        Assert.areSame(1, listTwo.size(), 'model should be added to list two');
561
 
        Assert.areSame(1, listThree.size(), 'model should be added to list three');
562
 
 
563
 
        model.destroy();
564
 
 
565
 
        Assert.areSame(0, listOne.size(), 'model should be removed from list one');
566
 
        Assert.areSame(0, listTwo.size(), 'model should be removed from list two');
567
 
        Assert.areSame(0, listThree.size(), 'model should be removed from list three');
568
 
    }
569
 
}));
570
 
 
571
 
// -- Model: Attributes and Properties -----------------------------------------
572
 
modelSuite.add(new Y.Test.Case({
573
 
    name: 'Attributes and Properties',
574
 
 
575
 
    setUp: function () {
576
 
        this.TestModel = Y.Base.create('testModel', Y.Model, [], {
577
 
            idAttribute: 'customId'
578
 
        }, {
579
 
            ATTRS: {
580
 
                customId: {value: ''},
581
 
                foo: {value: ''}
582
 
            }
583
 
        });
584
 
    },
585
 
 
586
 
    tearDown: function () {
587
 
        delete this.TestModel;
588
 
    },
589
 
 
590
 
    'Attributes should be settable at instantiation time': function () {
591
 
        var model = new this.TestModel({foo: 'foo'});
592
 
        Assert.areSame('foo', model.get('foo'));
593
 
    },
594
 
 
595
 
    'Custom id attribute should be settable at instantiation time': function () {
596
 
        var model;
597
 
 
598
 
        // We need to set and get the id and customId attributes in various
599
 
        // orders to ensure there are no issues due to the attributes being
600
 
        // lazily added.
601
 
 
602
 
        model = new this.TestModel({customId: 'foo'});
603
 
        Assert.areSame('foo', model.get('customId'));
604
 
        Assert.areSame('foo', model.get('id'));
605
 
 
606
 
        model = new this.TestModel({customId: 'foo'});
607
 
        Assert.areSame('foo', model.get('id'));
608
 
        Assert.areSame('foo', model.get('customId'));
609
 
 
610
 
        model = new this.TestModel({id: 'foo'});
611
 
        Assert.areSame('foo', model.get('customId'));
612
 
        Assert.areSame('foo', model.get('id'));
613
 
 
614
 
        model = new this.TestModel({id: 'foo'});
615
 
        Assert.areSame('foo', model.get('id'));
616
 
        Assert.areSame('foo', model.get('customId'));
617
 
    },
618
 
 
619
 
    '`id` attribute should be an alias for the custom id attribute': function () {
620
 
        var calls = 0,
621
 
            model = new this.TestModel();
622
 
 
623
 
        model.on('change', function (e) {
624
 
            calls += 1;
625
 
 
626
 
            Assert.areSame('foo', e.changed.customId.newVal);
627
 
            Assert.areSame('foo', e.changed.id.newVal);
628
 
        });
629
 
 
630
 
        model.set('id', 'foo');
631
 
 
632
 
        Assert.areSame(1, calls);
633
 
    },
634
 
 
635
 
    '`changed` property should be a hash of attributes that have changed since last save() or load()': function () {
636
 
        var model = new this.TestModel();
637
 
 
638
 
        Assert.isObject(model.changed);
639
 
        ObjectAssert.ownsNoKeys(model.changed);
640
 
 
641
 
        model.set('foo', 'foo');
642
 
        Assert.areSame('foo', model.changed.foo);
643
 
 
644
 
        model.setAttrs({foo: 'bar', bar: 'baz'});
645
 
        ObjectAssert.areEqual({foo: 'bar', bar: 'baz'}, model.changed);
646
 
 
647
 
        model.save();
648
 
        ObjectAssert.ownsNoKeys(model.changed);
649
 
 
650
 
        model.set('foo', 'foo');
651
 
        model.load();
652
 
        ObjectAssert.ownsNoKeys(model.changed);
653
 
    },
654
 
 
655
 
    'clientId attribute should be automatically generated': function () {
656
 
        var model = new Y.Model();
657
 
 
658
 
        Assert.isString(model.get('clientId'));
659
 
        Assert.isTrue(!!model.get('clientId'));
660
 
    },
661
 
 
662
 
    '`lastChange` property should contain attributes that changed in the last `change` event': function () {
663
 
        var model = new this.TestModel();
664
 
 
665
 
        Assert.isObject(model.lastChange);
666
 
        ObjectAssert.ownsNoKeys(model.lastChange);
667
 
 
668
 
        model.set('foo', 'foo');
669
 
        Assert.areSame(1, Y.Object.size(model.lastChange));
670
 
        ObjectAssert.ownsKeys(['newVal', 'prevVal', 'src'], model.lastChange.foo);
671
 
        Assert.areSame('', model.lastChange.foo.prevVal);
672
 
        Assert.areSame('foo', model.lastChange.foo.newVal);
673
 
        Assert.isNull(model.lastChange.foo.src);
674
 
 
675
 
        model.set('bar', 'bar', {src: 'test'});
676
 
        Assert.areSame(1, Y.Object.size(model.lastChange));
677
 
        Assert.areSame('test', model.lastChange.bar.src);
678
 
 
679
 
        model.set('foo', 'bar', {silent: true});
680
 
        Assert.areSame(1, Y.Object.size(model.lastChange));
681
 
        Assert.areSame('bar', model.lastChange.foo.newVal);
682
 
    },
683
 
 
684
 
    '`lists` property should be an array of ModelList instances that contain this model': function () {
685
 
        var calls = 0,
686
 
            model = new this.TestModel(),
687
 
 
688
 
            lists = [
689
 
                new Y.ModelList({model: this.TestModel}),
690
 
                new Y.ModelList({model: this.TestModel})
691
 
            ];
692
 
 
693
 
        Assert.isArray(model.lists);
694
 
 
695
 
        function onChange() {
696
 
            calls += 1;
697
 
        }
698
 
 
699
 
        lists[0].on('*:change', onChange);
700
 
        lists[1].on('*:change', onChange);
701
 
 
702
 
        lists[0].add(model);
703
 
        lists[1].add(model);
704
 
 
705
 
        ArrayAssert.itemsAreSame(lists, model.lists);
706
 
 
707
 
        model.set('foo', 'foo');
708
 
 
709
 
        Assert.areSame(2, calls);
710
 
    }
711
 
}));
712
 
 
713
 
// -- Model: Methods -----------------------------------------------------------
714
 
modelSuite.add(new Y.Test.Case({
715
 
    name: 'Methods',
716
 
 
717
 
    setUp: function () {
718
 
        this.TestModel = Y.Base.create('testModel', Y.Model, [], {}, {
719
 
            ATTRS: {
720
 
                foo: {value: ''},
721
 
                bar: {value: ''}
722
 
            }
723
 
        });
724
 
    },
725
 
 
726
 
    tearDown: function () {
727
 
        delete this.TestModel;
728
 
    },
729
 
 
730
 
    'generateClientId() should generate a unique client id': function () {
731
 
        var model    = new this.TestModel(),
732
 
            firstId  = model.generateClientId(),
733
 
            secondId = model.generateClientId();
734
 
 
735
 
        Assert.isString(firstId);
736
 
        Assert.areNotSame(firstId, secondId);
737
 
        Assert.isTrue(firstId.indexOf(this.TestModel.NAME) === 0);
738
 
    },
739
 
 
740
 
    'getAsHTML() should return an HTML-escaped attribute value': function () {
741
 
        var value = '<div id="foo">hello!</div>',
742
 
            model = new this.TestModel({foo: value});
743
 
 
744
 
        Assert.areSame(Y.Escape.html(value), model.getAsHTML('foo'));
745
 
    },
746
 
 
747
 
    'getAsURL() should return a URL-encoded attribute value': function () {
748
 
        var value = 'foo & bar = baz',
749
 
            model = new this.TestModel({foo: value});
750
 
 
751
 
        Assert.areSame(encodeURIComponent(value), model.getAsURL('foo'));
752
 
    },
753
 
 
754
 
    'isModified() should return true if the model is new': function () {
755
 
        var model = new this.TestModel();
756
 
        Assert.isTrue(model.isModified());
757
 
 
758
 
        model = new this.TestModel({id: 'foo'});
759
 
        Assert.isFalse(model.isModified());
760
 
    },
761
 
 
762
 
    'isModified() should return true if the model has changed since it was last saved': function () {
763
 
        var model = new this.TestModel({id: 'foo'});
764
 
        Assert.isFalse(model.isModified());
765
 
 
766
 
        model.set('foo', 'bar');
767
 
        Assert.isTrue(model.isModified());
768
 
 
769
 
        model.save();
770
 
        Assert.isFalse(model.isModified());
771
 
    },
772
 
 
773
 
    'isNew() should return true if the model is new': function () {
774
 
        var model = new this.TestModel();
775
 
        Assert.isTrue(model.isNew());
776
 
 
777
 
        model = new this.TestModel({id: 'foo'});
778
 
        Assert.isFalse(model.isNew());
779
 
 
780
 
        model = new this.TestModel({id: 0});
781
 
        Assert.isFalse(model.isNew());
782
 
    },
783
 
 
784
 
    'load() should delegate to sync()': function () {
785
 
        var calls = 0,
786
 
            model = new this.TestModel(),
787
 
            opts  = {};
788
 
 
789
 
        model.sync = function (action, options, callback) {
790
 
            calls += 1;
791
 
 
792
 
            Assert.areSame('read', action);
793
 
            Assert.areSame(opts, options);
794
 
            Assert.isFunction(callback);
795
 
 
796
 
            callback();
797
 
        };
798
 
 
799
 
        model.load(opts);
800
 
        Assert.areSame(1, calls);
801
 
    },
802
 
 
803
 
    'load() should reset this.changed when loading succeeds': function () {
804
 
        var model = new this.TestModel();
805
 
 
806
 
        model.set('foo', 'bar');
807
 
        Assert.areSame(1, Y.Object.size(model.changed));
808
 
 
809
 
        model.load();
810
 
        Assert.areSame(0, Y.Object.size(model.changed));
811
 
    },
812
 
 
813
 
    'load() should be chainable and should call the callback if one was provided': function () {
814
 
        var calls = 0,
815
 
            model = new this.TestModel();
816
 
 
817
 
        Assert.areSame(model, model.load());
818
 
        Assert.areSame(model, model.load({}));
819
 
 
820
 
        Assert.areSame(model, model.load(function (err) {
821
 
            calls += 1;
822
 
            Assert.isUndefined(err);
823
 
        }));
824
 
 
825
 
        Assert.areSame(model, model.load({}, function () {
826
 
            calls += 1;
827
 
        }));
828
 
 
829
 
        Assert.areSame(2, calls);
830
 
    },
831
 
 
832
 
    'parse() should parse a JSON string and return an object': function () {
833
 
        var model    = new this.TestModel(),
834
 
            response = model.parse('{"foo": "bar"}');
835
 
 
836
 
        Assert.isObject(response);
837
 
        Assert.areSame('bar', response.foo);
838
 
    },
839
 
 
840
 
    'parse() should not try to parse non-strings': function () {
841
 
        var model  = new this.TestModel(),
842
 
            array  = ['foo', 'bar'],
843
 
            object = {foo: 'bar'};
844
 
 
845
 
        Assert.areSame(array, model.parse(array));
846
 
        Assert.areSame(object, model.parse(object));
847
 
    },
848
 
 
849
 
    'save() should delegate to sync()': function () {
850
 
        var calls = 0,
851
 
            model = new this.TestModel(),
852
 
            opts  = {};
853
 
 
854
 
        model.sync = function (action, options, callback) {
855
 
            calls += 1;
856
 
 
857
 
            Assert.areSame('create', action);
858
 
            Assert.areSame(opts, options);
859
 
            Assert.isFunction(callback);
860
 
 
861
 
            // Give the model an id so it will no longer be new.
862
 
            callback(null, {id: 'foo'});
863
 
        };
864
 
 
865
 
        model.save(opts);
866
 
 
867
 
        Assert.areSame('foo', model.get('id'), "model id should be updated after save");
868
 
 
869
 
        model.sync = function (action) {
870
 
            calls += 1;
871
 
            Assert.areSame('update', action);
872
 
        };
873
 
 
874
 
        model.save();
875
 
 
876
 
        Assert.areSame(2, calls);
877
 
    },
878
 
 
879
 
    'save() should reset this.changed when saving succeeds': function () {
880
 
        var model = new this.TestModel();
881
 
 
882
 
        model.set('foo', 'bar');
883
 
        Assert.areSame(1, Y.Object.size(model.changed));
884
 
 
885
 
        model.save();
886
 
        Assert.areSame(0, Y.Object.size(model.changed));
887
 
    },
888
 
 
889
 
    'save() should be chainable and should call the callback if one was provided': function () {
890
 
        var calls = 0,
891
 
            model = new this.TestModel();
892
 
 
893
 
        Assert.areSame(model, model.save());
894
 
        Assert.areSame(model, model.save({}));
895
 
 
896
 
        Assert.areSame(model, model.save(function (err) {
897
 
            calls += 1;
898
 
            Assert.isUndefined(err);
899
 
        }));
900
 
 
901
 
        Assert.areSame(model, model.save({}, function () {
902
 
            calls += 1;
903
 
        }));
904
 
 
905
 
        Assert.areSame(2, calls);
906
 
    },
907
 
 
908
 
    'set() should set the value of a single attribute': function () {
909
 
        var model = new this.TestModel();
910
 
 
911
 
        Assert.areSame('', model.get('foo'));
912
 
        Assert.areSame(model, model.set('foo', 'bar'), 'set() should be chainable');
913
 
        Assert.areSame('bar', model.get('foo'));
914
 
    },
915
 
 
916
 
    'setAttrs() should set the values of multiple attributes': function () {
917
 
        var model = new this.TestModel();
918
 
 
919
 
        Assert.areSame('', model.get('foo'));
920
 
        Assert.areSame('', model.get('bar'));
921
 
        Assert.areSame(model, model.setAttrs({foo: 'foo', bar: 'bar'}), 'setAttrs() should be chainable');
922
 
        Assert.areSame('foo', model.get('foo'));
923
 
        Assert.areSame('bar', model.get('bar'));
924
 
    },
925
 
 
926
 
    'sync() should just call the supplied callback by default': function () {
927
 
        var calls = 0,
928
 
            model = new this.TestModel();
929
 
 
930
 
        model.sync(function (err) {
931
 
            calls += 1;
932
 
            Assert.isUndefined(err);
933
 
        });
934
 
 
935
 
        Assert.areSame(1, calls);
936
 
    },
937
 
 
938
 
    "toJSON() should return a copy of the model's attributes, minus excluded ones": function () {
939
 
        var attrs = {id: 'id', foo: 'foo', bar: 'bar'},
940
 
            model = new this.TestModel(attrs),
941
 
            CustomTestModel, json;
942
 
 
943
 
        json = model.toJSON();
944
 
        Assert.areSame(3, Y.Object.size(json));
945
 
        ObjectAssert.ownsKeys(['id', 'foo', 'bar'], json);
946
 
        ObjectAssert.areEqual(attrs, json);
947
 
 
948
 
        // When there's a custom id attribute, the 'id' attribute should be
949
 
        // excluded.
950
 
        CustomTestModel = Y.Base.create('customTestModel', Y.Model, [], {
951
 
            idAttribute: 'customId'
952
 
        }, {
953
 
            ATTRS: {
954
 
                customId: {value: ''},
955
 
                foo     : {value: ''},
956
 
                bar     : {value: ''}
957
 
            }
958
 
        });
959
 
 
960
 
        attrs = {customId: 'id', foo: 'foo', bar: 'bar'};
961
 
        model = new CustomTestModel(attrs);
962
 
        json  = model.toJSON();
963
 
 
964
 
        Assert.areSame(3, Y.Object.size(json));
965
 
        ObjectAssert.ownsKeys(['customId', 'foo', 'bar'], json);
966
 
        ObjectAssert.areEqual(attrs, json);
967
 
    },
968
 
 
969
 
    'undo() should revert the previous change to the model': function () {
970
 
        var attrs = {id: 'id', foo: 'foo', bar: 'bar'},
971
 
            model = new this.TestModel(attrs);
972
 
 
973
 
        ObjectAssert.areEqual(attrs, model.toJSON());
974
 
 
975
 
        model.setAttrs({foo: 'moo', bar: 'quux'});
976
 
        ObjectAssert.areEqual({id: 'id', foo: 'moo', bar: 'quux'}, model.toJSON());
977
 
 
978
 
        Assert.areSame(model, model.undo(), 'undo() should be chainable');
979
 
        ObjectAssert.areEqual(attrs, model.toJSON());
980
 
    },
981
 
 
982
 
    'undo() should revert only the specified attributes when attributes are specified': function () {
983
 
        var model = new this.TestModel({id: 'id', foo: 'foo', bar: 'bar'});
984
 
 
985
 
        model.setAttrs({foo: 'moo', bar: 'quux'});
986
 
 
987
 
        model.undo(['foo']);
988
 
        ObjectAssert.areEqual({id: 'id', foo: 'foo', bar: 'quux'}, model.toJSON());
989
 
    },
990
 
 
991
 
    'undo() should pass options to setAttrs()': function () {
992
 
        var calls = 0,
993
 
            model = new this.TestModel({id: 'id', foo: 'foo', bar: 'bar'});
994
 
 
995
 
        model.setAttrs({foo: 'moo', bar: 'quux'});
996
 
 
997
 
        model.on('change', function (e) {
998
 
            calls += 1;
999
 
            Assert.areSame('test', e.changed.foo.src);
1000
 
        });
1001
 
 
1002
 
        model.undo(null, {src: 'test'});
1003
 
        Assert.areSame(1, calls);
1004
 
    },
1005
 
 
1006
 
    'undo() should do nothing when there is no previous change to revert': function () {
1007
 
        var model = new this.TestModel();
1008
 
 
1009
 
        model.on('change', function () {
1010
 
            Assert.fail('`change` should not be called');
1011
 
        });
1012
 
 
1013
 
        model.undo();
1014
 
    },
1015
 
 
1016
 
    'validate() should be a noop function by default': function () {
1017
 
        var model = new this.TestModel();
1018
 
 
1019
 
        Assert.isFunction(model.validate);
1020
 
        Assert.isUndefined(model.validate());
1021
 
    },
1022
 
 
1023
 
    'validate() should only be called on save()': function () {
1024
 
        var calls = 0,
1025
 
            model = new this.TestModel();
1026
 
 
1027
 
        model.validate = function (attrs) {
1028
 
            calls += 1;
1029
 
            Y.ObjectAssert.areEqual(model.toJSON(), attrs);
1030
 
        };
1031
 
 
1032
 
        model.set('foo', 'bar');
1033
 
        model.set('foo', 'baz');
1034
 
        model.save();
1035
 
 
1036
 
        Assert.areSame(1, calls);
1037
 
    },
1038
 
 
1039
 
    'a validation failure should abort a save() call': function () {
1040
 
        var calls         = 0,
1041
 
            errors        = 0,
1042
 
            model         = new this.TestModel(),
1043
 
            saveCallbacks = 0;
1044
 
 
1045
 
        model.validate = function (attrs) {
1046
 
            calls += 1;
1047
 
            return 'OMG invalid!';
1048
 
        };
1049
 
 
1050
 
        model.sync = function () {
1051
 
            Assert.fail('sync() should not be called on validation failure');
1052
 
        };
1053
 
 
1054
 
        model.on('error', function (e) {
1055
 
            errors += 1;
1056
 
            Assert.areSame('OMG invalid!', e.error);
1057
 
            Assert.areSame('validate', e.src);
1058
 
        });
1059
 
 
1060
 
        model.save(function (err, res) {
1061
 
            saveCallbacks += 1;
1062
 
            Assert.areSame('OMG invalid!', err);
1063
 
            Assert.isUndefined(res);
1064
 
        });
1065
 
 
1066
 
        Assert.areSame(1, calls);
1067
 
        Assert.areSame(1, saveCallbacks);
1068
 
        Assert.areSame(1, errors);
1069
 
    }
1070
 
}));
1071
 
 
1072
 
// -- Model: Events ------------------------------------------------------------
1073
 
modelSuite.add(new Y.Test.Case({
1074
 
    name: 'Events',
1075
 
 
1076
 
    setUp: function () {
1077
 
        this.TestModel = Y.Base.create('testModel', Y.Model, [], {}, {
1078
 
            ATTRS: {
1079
 
                foo: {value: ''},
1080
 
                bar: {value: ''},
1081
 
                baz: {value: ''}
1082
 
            }
1083
 
        });
1084
 
    },
1085
 
 
1086
 
    tearDown: function () {
1087
 
        delete this.TestModel;
1088
 
    },
1089
 
 
1090
 
    '`change` event should contain coalesced attribute changes': function () {
1091
 
        var calls = 0,
1092
 
            model = new this.TestModel();
1093
 
 
1094
 
        model.on('change', function (e) {
1095
 
            calls += 1;
1096
 
 
1097
 
            ObjectAssert.ownsKeys(['foo', 'bar'], e.changed);
1098
 
            Assert.areSame(2, Y.Object.size(e.changed));
1099
 
            ObjectAssert.ownsKeys(['newVal', 'prevVal', 'src'], e.changed.foo);
1100
 
            ObjectAssert.ownsKeys(['newVal', 'prevVal', 'src'], e.changed.bar);
1101
 
            Assert.areSame('foo', e.changed.foo.newVal);
1102
 
            Assert.areSame('', e.changed.foo.prevVal);
1103
 
            Assert.areSame('bar', e.changed.bar.newVal);
1104
 
            Assert.areSame('', e.changed.bar.prevVal);
1105
 
            Assert.areSame('test', e.changed.foo.src);
1106
 
            Assert.areSame('test', e.changed.bar.src);
1107
 
        });
1108
 
 
1109
 
        model.setAttrs({
1110
 
            foo: 'foo',
1111
 
            bar: 'bar'
1112
 
        }, {src: 'test'});
1113
 
 
1114
 
        Assert.areSame(1, calls);
1115
 
    },
1116
 
 
1117
 
    '`change` event should not fire when the _silent_ option is truthy': function () {
1118
 
        var model = new this.TestModel();
1119
 
 
1120
 
        model.on('change', function (e) {
1121
 
            Assert.fail('`change` should not fire');
1122
 
        });
1123
 
 
1124
 
        model.set('foo', 'bar', {silent: true});
1125
 
        model.setAttrs({bar: 'baz'}, {silent: true});
1126
 
    },
1127
 
 
1128
 
    '`error` event should fire when validation fails': function () {
1129
 
        var calls = 0,
1130
 
            model = new this.TestModel();
1131
 
 
1132
 
        model.validate = function (hash) {
1133
 
            return 'ERROR. ERROR. DOES NOT COMPUTE.';
1134
 
        };
1135
 
 
1136
 
        model.on('error', function (e) {
1137
 
            calls += 1;
1138
 
 
1139
 
            Assert.areSame('validate', e.src);
1140
 
            ObjectAssert.ownsKey('foo', e.attributes);
1141
 
            Assert.areSame('bar', e.attributes.foo);
1142
 
            Assert.areSame('ERROR. ERROR. DOES NOT COMPUTE.', e.error);
1143
 
        });
1144
 
 
1145
 
        model.set('foo', 'bar');
1146
 
        model.save();
1147
 
 
1148
 
        Assert.areSame(1, calls);
1149
 
    },
1150
 
 
1151
 
    '`error` event should fire when parsing fails': function () {
1152
 
        var calls = 0,
1153
 
            model = new this.TestModel();
1154
 
 
1155
 
        model.on('error', function (e) {
1156
 
            calls += 1;
1157
 
 
1158
 
            Assert.areSame('parse', e.src);
1159
 
            Y.assert(e.error instanceof Error);
1160
 
            Assert.areSame('moo', e.response);
1161
 
        });
1162
 
 
1163
 
        model.parse('moo');
1164
 
 
1165
 
        Assert.areSame(1, calls);
1166
 
    }
1167
 
}));
1168
 
 
1169
 
// -- ModelList Suite ----------------------------------------------------------
1170
 
modelListSuite = new Y.Test.Suite('ModelList');
1171
 
 
1172
 
// -- ModelList: Lifecycle -----------------------------------------------------
1173
 
modelListSuite.add(new Y.Test.Case({
1174
 
    name: 'Lifecycle',
1175
 
 
1176
 
    setUp: function () {
1177
 
        this.list = new Y.ModelList({model: Y.Model});
1178
 
    },
1179
 
 
1180
 
    tearDown: function () {
1181
 
        delete this.list;
1182
 
    },
1183
 
 
1184
 
    'ModelLists should have a `model` property': function () {
1185
 
        Assert.isNull(new Y.ModelList().model);
1186
 
    },
1187
 
 
1188
 
    'destructor should detach all models from the list': function () {
1189
 
        var model = new Y.Model();
1190
 
 
1191
 
        this.list.add(model);
1192
 
        Assert.areSame(this.list, model.lists[0]);
1193
 
 
1194
 
        this.list.destroy();
1195
 
        ArrayAssert.isEmpty(model.lists);
1196
 
    }
1197
 
}));
1198
 
 
1199
 
// -- ModelList: Methods -------------------------------------------------------
1200
 
modelListSuite.add(new Y.Test.Case({
1201
 
    name: 'Methods',
1202
 
 
1203
 
    setUp: function () {
1204
 
        this.TestModel = Y.Base.create('testModel', Y.Model, [], {}, {
1205
 
            ATTRS: {
1206
 
                foo: {value: ''},
1207
 
                bar: {value: ''}
1208
 
            }
1209
 
        });
1210
 
 
1211
 
        this.TestList = Y.Base.create('testList', Y.ModelList, []);
1212
 
 
1213
 
        this.createList = function (modelClass) {
1214
 
            return new this.TestList({model: modelClass || this.TestModel});
1215
 
        };
1216
 
 
1217
 
        this.createModel = function (config) {
1218
 
            return new this.TestModel(config);
1219
 
        };
1220
 
    },
1221
 
 
1222
 
    tearDown: function () {
1223
 
        delete this.createList;
1224
 
        delete this.createModel;
1225
 
        delete this.TestList;
1226
 
        delete this.TestModel;
1227
 
    },
1228
 
 
1229
 
    'add() should add a model to the list': function () {
1230
 
        var list  = this.createList(),
1231
 
            model = this.createModel(),
1232
 
            added;
1233
 
 
1234
 
        Assert.areSame(model, list.add(model));
1235
 
        Assert.areSame(1, list.size());
1236
 
 
1237
 
        added = list.add({foo: 'foo'});
1238
 
        Assert.isInstanceOf(this.TestModel, added);
1239
 
        Assert.areSame(2, list.size());
1240
 
        Assert.areSame('foo', added.get('foo'));
1241
 
    },
1242
 
 
1243
 
    'add() should add an array of models to the list': function () {
1244
 
        var list   = this.createList(),
1245
 
            models = [this.createModel(), this.createModel()],
1246
 
            added;
1247
 
 
1248
 
        ArrayAssert.itemsAreSame(models, list.add(models));
1249
 
        Assert.areSame(2, list.size());
1250
 
 
1251
 
        added = list.add([{foo: 'foo'}, {bar: 'bar'}]);
1252
 
        Assert.isInstanceOf(this.TestModel, added[0]);
1253
 
        Assert.isInstanceOf(this.TestModel, added[1]);
1254
 
        Assert.areSame(4, list.size());
1255
 
        Assert.areSame('foo', added[0].get('foo'));
1256
 
        Assert.areSame('bar', added[1].get('bar'));
1257
 
    },
1258
 
 
1259
 
    'comparator() should be undefined by default': function () {
1260
 
        Assert.isUndefined(this.createList().comparator);
1261
 
    },
1262
 
 
1263
 
    'models should be added in the proper position based on the comparator': function () {
1264
 
        var list = this.createList();
1265
 
 
1266
 
        list.comparator = function (model) {
1267
 
            return model.get('foo');
1268
 
        };
1269
 
 
1270
 
        list.add([{foo: 'z'}, {foo: 'a'}, {foo: 'x'}, {foo: 'y'}]);
1271
 
 
1272
 
        ArrayAssert.itemsAreSame(['a', 'x', 'y', 'z'], list.get('foo'));
1273
 
    },
1274
 
 
1275
 
    'create() should create or update a model, then add it to the list': function () {
1276
 
        var list  = this.createList(),
1277
 
            model = this.createModel();
1278
 
 
1279
 
        Assert.areSame(model, list.create(model));
1280
 
        Assert.areSame(1, list.size());
1281
 
 
1282
 
        Assert.isInstanceOf(this.TestModel, list.create({foo: 'foo'}));
1283
 
        Assert.areSame(2, list.size());
1284
 
    },
1285
 
 
1286
 
    'create() should call the callback if one is provided': function () {
1287
 
        var calls = 0,
1288
 
            list  = this.createList();
1289
 
 
1290
 
        list.create({}, {}, function (err) {
1291
 
            calls += 1;
1292
 
            Assert.isUndefined(err);
1293
 
        });
1294
 
 
1295
 
        list.create({}, function () { calls += 1; });
1296
 
 
1297
 
        Assert.areSame(2, calls);
1298
 
    },
1299
 
 
1300
 
    'create() should pass an error to the callback if one occurs': function () {
1301
 
        var calls = 0,
1302
 
            list  = this.createList(),
1303
 
            model = this.createModel();
1304
 
 
1305
 
        model.sync = function (action, options, callback) {
1306
 
            callback('Oh noes!');
1307
 
        };
1308
 
 
1309
 
        list.create(model, function (err) {
1310
 
            calls += 1;
1311
 
            Assert.areSame('Oh noes!', err);
1312
 
        });
1313
 
 
1314
 
        Assert.areSame(1, calls);
1315
 
    },
1316
 
 
1317
 
    'get() should return an array of attribute values from all models in the list': function () {
1318
 
        var list = this.createList();
1319
 
 
1320
 
        list.add([{foo: 'one'}, {foo: 'two'}]);
1321
 
        ArrayAssert.itemsAreSame(['one', 'two'], list.get('foo'));
1322
 
    },
1323
 
 
1324
 
    'get() should return a list attribute if there is one': function () {
1325
 
        var list = this.createList();
1326
 
 
1327
 
        list.addAttr('foo', {value: '<listfoo>'});
1328
 
        list.add([{foo: 'modelfoo-one'}, {foo: 'modelfoo-two'}]);
1329
 
 
1330
 
        Assert.areSame('<listfoo>', list.get('foo'));
1331
 
    },
1332
 
 
1333
 
    'getAsHTML() should return an array of HTML-escaped attribute values': function () {
1334
 
        var list = this.createList();
1335
 
 
1336
 
        list.add([{foo: '<foo>'}, {foo: '<bar>'}]);
1337
 
        ArrayAssert.itemsAreSame(['&lt;foo&gt;', '&lt;bar&gt;'], list.getAsHTML('foo'));
1338
 
    },
1339
 
 
1340
 
    'getAsHTML() should return a list attribute if there is one': function () {
1341
 
        var list = this.createList();
1342
 
 
1343
 
        list.addAttr('foo', {value: '<listfoo>'});
1344
 
        list.add([{foo: 'modelfoo-one'}, {foo: 'modelfoo-two'}]);
1345
 
 
1346
 
        Assert.areSame('&lt;listfoo&gt;', list.getAsHTML('foo'));
1347
 
    },
1348
 
 
1349
 
    'getAsURL() should return an array of URL-encoded attribute values': function () {
1350
 
        var list = this.createList();
1351
 
 
1352
 
        list.add([{foo: 'a b'}, {foo: 'c d'}]);
1353
 
        ArrayAssert.itemsAreSame(['a%20b', 'c%20d'], list.getAsURL('foo'));
1354
 
    },
1355
 
 
1356
 
    'getAsURL() should return a list attribute if there is one': function () {
1357
 
        var list = this.createList();
1358
 
 
1359
 
        list.addAttr('foo', {value: 'list foo'});
1360
 
        list.add([{foo: 'modelfoo-one'}, {foo: 'modelfoo-two'}]);
1361
 
 
1362
 
        Assert.areSame('list%20foo', list.getAsURL('foo'));
1363
 
    },
1364
 
 
1365
 
    'getByClientId() should look up a model by its clientId': function () {
1366
 
        var list  = this.createList(),
1367
 
            model = list.add({});
1368
 
 
1369
 
        Assert.areSame(model, list.getByClientId(model.get('clientId')));
1370
 
        Assert.isNull(list.getByClientId('bogus'));
1371
 
    },
1372
 
 
1373
 
    'getById() should look up a model by its id': function () {
1374
 
        var list  = this.createList(),
1375
 
            model = list.add({id: 'foo'});
1376
 
 
1377
 
        Assert.areSame(model, list.getById(model.get('id')));
1378
 
        Assert.isNull(list.getById('bogus'));
1379
 
    },
1380
 
 
1381
 
    'getById() should work with numeric ids': function () {
1382
 
        var list  = this.createList(),
1383
 
            model = list.add({id: 0});
1384
 
 
1385
 
        Assert.areSame(model, list.getById(0));
1386
 
    },
1387
 
 
1388
 
    'getById() should work with custom ids': function () {
1389
 
        var CustomModel = Y.Base.create('customModel', Y.Model, [], {
1390
 
                idAttribute: 'customId'
1391
 
            }, {
1392
 
                ATTRS: {
1393
 
                    customId: {value: ''}
1394
 
                }
1395
 
            }),
1396
 
 
1397
 
            list  = this.createList(CustomModel),
1398
 
            model = list.add({customId: 'foo'});
1399
 
 
1400
 
        Assert.areSame(model, list.getById(model.get('customId')));
1401
 
    },
1402
 
 
1403
 
    'invoke() should call the named method on every model in the list': function () {
1404
 
        var list = this.createList(),
1405
 
            results;
1406
 
 
1407
 
        list.add([{}, {}]);
1408
 
        results = list.invoke('set', 'foo', 'foo');
1409
 
 
1410
 
        ArrayAssert.itemsAreSame(list.toArray(), results, 'invoke should return an array of return values');
1411
 
        ArrayAssert.itemsAreSame(['foo', 'foo'], list.get('foo'));
1412
 
    },
1413
 
 
1414
 
    'item() should return the model at the specified index': function () {
1415
 
        var list = this.createList();
1416
 
 
1417
 
        list.add([{foo: 'zero'}, {foo: 'one'}]);
1418
 
 
1419
 
        Assert.areSame('zero', list.item(0).get('foo'));
1420
 
        Assert.areSame('one', list.item(1).get('foo'));
1421
 
    },
1422
 
 
1423
 
    'load() should delegate to sync()': function () {
1424
 
        var calls = 0,
1425
 
            list  = this.createList(),
1426
 
            opts  = {};
1427
 
 
1428
 
        list.sync = function (action, options, callback) {
1429
 
            calls += 1;
1430
 
 
1431
 
            Assert.areSame('read', action);
1432
 
            Assert.areSame(opts, options);
1433
 
            Assert.isFunction(callback);
1434
 
 
1435
 
            callback();
1436
 
        };
1437
 
 
1438
 
        list.load(opts);
1439
 
        Assert.areSame(1, calls);
1440
 
    },
1441
 
 
1442
 
    'load() should be chainable and should call the callback if one was provided': function () {
1443
 
        var calls = 0,
1444
 
            list  = this.createList();
1445
 
 
1446
 
        Assert.areSame(list, list.load());
1447
 
        Assert.areSame(list, list.load({}));
1448
 
 
1449
 
        Assert.areSame(list, list.load(function (err) {
1450
 
            calls += 1;
1451
 
            Assert.isUndefined(err);
1452
 
        }));
1453
 
 
1454
 
        Assert.areSame(list, list.load({}, function () {
1455
 
            calls += 1;
1456
 
        }));
1457
 
 
1458
 
        Assert.areSame(2, calls);
1459
 
    },
1460
 
 
1461
 
    'map() should execute a function on every model in the list and return an array of return values': function () {
1462
 
        var list = this.createList(),
1463
 
            obj  = {},
1464
 
            results;
1465
 
 
1466
 
        list.add([{foo: 'zero'}, {foo: 'one'}]);
1467
 
 
1468
 
        results = list.map(function (model) {
1469
 
            Assert.areSame(obj, this);
1470
 
            return model.get('foo');
1471
 
        }, obj);
1472
 
 
1473
 
        ArrayAssert.itemsAreSame(['zero', 'one'], results);
1474
 
    },
1475
 
 
1476
 
    'parse() should parse a JSON string and return an object': function () {
1477
 
        var list     = this.createList(),
1478
 
            response = list.parse('[{"foo": "bar"}]');
1479
 
 
1480
 
        Assert.isArray(response);
1481
 
        Assert.areSame('bar', response[0].foo);
1482
 
    },
1483
 
 
1484
 
    'parse() should not try to parse non-strings': function () {
1485
 
        var list   = this.createList(),
1486
 
            array  = ['foo', 'bar'],
1487
 
            object = {foo: 'bar'};
1488
 
 
1489
 
        Assert.areSame(array, list.parse(array));
1490
 
        Assert.areSame(object, list.parse(object));
1491
 
    },
1492
 
 
1493
 
    'reset() should replace all models in the list': function () {
1494
 
        var list   = this.createList(),
1495
 
            models = list.add([{foo: 'zero'}, {foo: 'one'}]);
1496
 
 
1497
 
        Assert.areSame(list, list.reset([{foo: 'two'}, {foo: 'three'}]));
1498
 
        ArrayAssert.itemsAreSame(['two', 'three'], list.get('foo'));
1499
 
 
1500
 
        // Removed models should be cleanly detached.
1501
 
        Assert.isUndefined(models[0].list);
1502
 
        Assert.isUndefined(models[1].list);
1503
 
 
1504
 
        // And we should be able to re-add them.
1505
 
        list.reset(models);
1506
 
        ArrayAssert.itemsAreSame(['zero', 'one'], list.get('foo'));
1507
 
    },
1508
 
 
1509
 
    'reset() should sort the new models in the list': function () {
1510
 
        var list = this.createList();
1511
 
 
1512
 
        list.comparator = function (model) {
1513
 
            return model.get('bar');
1514
 
        };
1515
 
 
1516
 
        list.reset([
1517
 
            {foo: 'item 1', bar: 1},
1518
 
            {foo: 'item 4', bar: 4},
1519
 
            {foo: 'item 3', bar: 3},
1520
 
            {foo: 'item 5', bar: 5},
1521
 
            {foo: 'item 2', bar: 2}
1522
 
        ]);
1523
 
 
1524
 
        ArrayAssert.itemsAreSame([1, 2, 3, 4, 5], list.get('bar'));
1525
 
    },
1526
 
 
1527
 
    'reset() with no args should clear the list': function () {
1528
 
        var list   = this.createList(),
1529
 
            models = list.add([{foo: 'zero'}, {foo: 'one'}]);
1530
 
 
1531
 
        Assert.areSame(2, list.size());
1532
 
        list.reset();
1533
 
        Assert.areSame(0, list.size());
1534
 
    },
1535
 
 
1536
 
    'remove() should remove a single model from the list': function () {
1537
 
        var list = this.createList();
1538
 
 
1539
 
        list.add([{foo: 'zero'}, {foo: 'one'}]);
1540
 
 
1541
 
        Assert.areSame('zero', list.remove(list.item(0)).get('foo'));
1542
 
        Assert.areSame(1, list.size());
1543
 
    },
1544
 
 
1545
 
    'remove() should remove an array of models from the list': function () {
1546
 
        var list = this.createList(),
1547
 
            removed;
1548
 
 
1549
 
        list.add([{foo: 'zero'}, {foo: 'one'}]);
1550
 
        removed = list.remove([list.item(0), list.item(1)]);
1551
 
 
1552
 
        Assert.areSame('zero', removed[0].get('foo'));
1553
 
        Assert.areSame('one', removed[1].get('foo'));
1554
 
        Assert.areSame(0, list.size());
1555
 
    },
1556
 
 
1557
 
    // 'set() should set a single attribute value on all models in the list': function () {
1558
 
    //
1559
 
    // },
1560
 
    //
1561
 
    // 'setAttrs() should set multiple attribute values on all models in the list': function () {
1562
 
    //
1563
 
    // },
1564
 
 
1565
 
    'sort() should re-sort the list': function () {
1566
 
        var list = this.createList();
1567
 
 
1568
 
        list.add([{foo: 'z'}, {foo: 'a'}, {foo: 'x'}, {foo: 'y'}]);
1569
 
 
1570
 
        ArrayAssert.itemsAreSame(['z', 'a', 'x', 'y'], list.get('foo'));
1571
 
 
1572
 
        list.comparator = function (model) {
1573
 
            return model.get('foo');
1574
 
        };
1575
 
 
1576
 
        Assert.areSame(list, list.sort(), 'sort() should be chainable');
1577
 
        ArrayAssert.itemsAreSame(['a', 'x', 'y', 'z'], list.get('foo'));
1578
 
 
1579
 
    },
1580
 
 
1581
 
    'sync() should just call the supplied callback by default': function () {
1582
 
        var calls = 0,
1583
 
            list  = this.createList();
1584
 
 
1585
 
        list.sync(function (err) {
1586
 
            calls += 1;
1587
 
            Assert.isUndefined(err);
1588
 
        });
1589
 
 
1590
 
        Assert.areSame(1, calls);
1591
 
    },
1592
 
 
1593
 
    'toArray() should return an array containing all the models in the list': function () {
1594
 
        var list   = this.createList(),
1595
 
            models = list.add([{}, {}]);
1596
 
 
1597
 
        ArrayAssert.itemsAreSame(models, list.toArray());
1598
 
    },
1599
 
 
1600
 
    'toJSON() should return an array of model hashes': function () {
1601
 
        var list   = this.createList(),
1602
 
            models = list.add([{foo: 'zero'}, {foo: 'one'}]),
1603
 
            json   = list.toJSON();
1604
 
 
1605
 
        Assert.isArray(json);
1606
 
        ObjectAssert.areEqual(models[0].toJSON(), json[0]);
1607
 
        ObjectAssert.areEqual(models[1].toJSON(), json[1]);
1608
 
    }
1609
 
}));
1610
 
 
1611
 
// -- ModelList: Events --------------------------------------------------------
1612
 
modelListSuite.add(new Y.Test.Case({
1613
 
    name: 'Events',
1614
 
 
1615
 
    setUp: function () {
1616
 
        this.TestModel = Y.Base.create('testModel', Y.Model, [], {}, {
1617
 
            ATTRS: {
1618
 
                foo: {value: ''},
1619
 
                bar: {value: ''}
1620
 
            }
1621
 
        });
1622
 
 
1623
 
        this.TestList = Y.Base.create('testList', Y.ModelList, []);
1624
 
 
1625
 
        this.createList = function (modelClass) {
1626
 
            return new this.TestList({model: modelClass || this.TestModel});
1627
 
        };
1628
 
 
1629
 
        this.createModel = function (config) {
1630
 
            return new this.TestModel(config);
1631
 
        };
1632
 
    },
1633
 
 
1634
 
    tearDown: function () {
1635
 
        delete this.createList;
1636
 
        delete this.createModel;
1637
 
        delete this.TestList;
1638
 
        delete this.TestModel;
1639
 
    },
1640
 
 
1641
 
    '`add` event should fire when a model is added': function () {
1642
 
        var calls = 0,
1643
 
            list  = this.createList(),
1644
 
            model = this.createModel();
1645
 
 
1646
 
        list.once('add', function (e) {
1647
 
            calls += 1;
1648
 
 
1649
 
            Assert.areSame(model, e.model);
1650
 
            Assert.areSame(0, e.index);
1651
 
            Assert.areSame('test', e.src);
1652
 
        });
1653
 
 
1654
 
        list.add(model, {src: 'test'});
1655
 
 
1656
 
        list.after('add', function (e) {
1657
 
            calls += 1;
1658
 
        });
1659
 
 
1660
 
        list.add([{}, {}]);
1661
 
 
1662
 
        Assert.areSame(3, calls);
1663
 
    },
1664
 
 
1665
 
    '`add` event should be preventable': function () {
1666
 
        var calls = 0,
1667
 
            list  = this.createList();
1668
 
 
1669
 
        list.on('add', function (e) {
1670
 
            calls += 1;
1671
 
            e.preventDefault();
1672
 
        });
1673
 
 
1674
 
        list.after('add', function () {
1675
 
            Assert.fail('add event should be prevented');
1676
 
        });
1677
 
 
1678
 
        list.add({});
1679
 
 
1680
 
        Assert.areSame(1, calls);
1681
 
        Assert.areSame(0, list.size());
1682
 
    },
1683
 
 
1684
 
    '`add` event should not fire when a model is added silently': function () {
1685
 
        var list = this.createList();
1686
 
 
1687
 
        list.on('add', function () {
1688
 
            Assert.fail('add event should not fire');
1689
 
        });
1690
 
 
1691
 
        list.add({}, {silent: true});
1692
 
        list.add([{}, {}], {silent: true});
1693
 
 
1694
 
        Assert.areSame(3, list.size());
1695
 
    },
1696
 
 
1697
 
    '`change` event should bubble up from models': function () {
1698
 
        var calls = 0,
1699
 
            list  = this.createList(),
1700
 
            model = list.add({});
1701
 
 
1702
 
        list.on('*:change', function (e) {
1703
 
            calls += 1;
1704
 
 
1705
 
            Assert.areSame(model, e.target);
1706
 
            Assert.areSame(list, e.currentTarget);
1707
 
        });
1708
 
 
1709
 
        model.set('foo', 'foo').set('bar', 'bar');
1710
 
 
1711
 
        Assert.areSame(2, calls);
1712
 
    },
1713
 
 
1714
 
    '`error` event should bubble up from models': function () {
1715
 
        var calls = 0,
1716
 
            list  = this.createList(),
1717
 
            model = list.add({});
1718
 
 
1719
 
        model.validate = function (hash) {
1720
 
            if (hash.foo === 'invalid') {
1721
 
                return 'fail!';
1722
 
            }
1723
 
        };
1724
 
 
1725
 
        list.on('*:error', function (e) {
1726
 
            calls += 1;
1727
 
 
1728
 
            Assert.areSame(model, e.target);
1729
 
            Assert.areSame(list, e.currentTarget);
1730
 
        });
1731
 
 
1732
 
        model.set('foo', 'invalid');
1733
 
        model.save();
1734
 
 
1735
 
        Assert.areSame(1, calls);
1736
 
    },
1737
 
 
1738
 
    '`error` event should fire when a duplicate model is added': function () {
1739
 
        var calls = 0,
1740
 
            list  = this.createList(),
1741
 
            model = this.createModel();
1742
 
 
1743
 
        list.on('error', function (e) {
1744
 
            calls += 1;
1745
 
 
1746
 
            Assert.areSame(model, e.model);
1747
 
            Assert.areSame('add', e.src);
1748
 
        });
1749
 
 
1750
 
        list.add(model);
1751
 
        list.add(model, {src: 'test'});
1752
 
        list.add({});
1753
 
 
1754
 
        Assert.areSame(1, calls);
1755
 
    },
1756
 
 
1757
 
    "`error` event should fire when a model that isn't in the list is removed": function () {
1758
 
        var calls = 0,
1759
 
            list  = this.createList(),
1760
 
            model = this.createModel();
1761
 
 
1762
 
        list.on('error', function (e) {
1763
 
            calls += 1;
1764
 
 
1765
 
            Assert.areSame(model, e.model);
1766
 
            Assert.areSame('remove', e.src);
1767
 
        });
1768
 
 
1769
 
        list.add(model);
1770
 
        list.remove(model);
1771
 
        list.remove(model, {src: 'test'});
1772
 
 
1773
 
        Assert.areSame(1, calls);
1774
 
    },
1775
 
 
1776
 
    "`error` event should fire when a sync layer response can't be parsed": function () {
1777
 
        var calls    = 0,
1778
 
            list     = this.createList(),
1779
 
            response = 'foo bar baz';
1780
 
 
1781
 
        list.once('error', function (e) {
1782
 
            calls += 1;
1783
 
 
1784
 
            Assert.areSame(response, e.response);
1785
 
            Assert.areSame('parse', e.src);
1786
 
        });
1787
 
 
1788
 
        list.parse(response);
1789
 
        list.parse('{"foo": "bar"}');
1790
 
 
1791
 
        Assert.areSame(1, calls);
1792
 
    },
1793
 
 
1794
 
    '`reset` event should fire when the list is reset or sorted': function () {
1795
 
        var calls  = 0,
1796
 
            list   = this.createList(),
1797
 
            models = [this.createModel(), this.createModel()];
1798
 
 
1799
 
        list.once('reset', function (e) {
1800
 
            calls += 1;
1801
 
 
1802
 
            ArrayAssert.itemsAreSame(models, e.models);
1803
 
            Assert.areSame('reset', e.src);
1804
 
            Assert.areSame('test', e.test);
1805
 
        });
1806
 
 
1807
 
        list.reset(models, {test: 'test'});
1808
 
 
1809
 
        list.after('reset', function (e) {
1810
 
            calls += 1;
1811
 
 
1812
 
            Assert.areSame('sort', e.src);
1813
 
            Assert.areSame('test', e.test);
1814
 
        });
1815
 
 
1816
 
        list.comparator = function (model) {
1817
 
            return model.get('clientId');
1818
 
        };
1819
 
 
1820
 
        list.sort({test: 'test'});
1821
 
 
1822
 
        Assert.areSame(2, calls);
1823
 
    },
1824
 
 
1825
 
    '`reset` event facade should contain sorted models': function () {
1826
 
        var calls = 0,
1827
 
            list  = this.createList();
1828
 
 
1829
 
        list.comparator = function (model) {
1830
 
            return model.get('bar');
1831
 
        };
1832
 
 
1833
 
        list.once('reset', function (e) {
1834
 
            var values = [];
1835
 
 
1836
 
            calls += 1;
1837
 
 
1838
 
            Y.Array.each(e.models, function (model) {
1839
 
                values.push(model.get('bar'));
1840
 
            });
1841
 
 
1842
 
            ArrayAssert.itemsAreSame([1, 2, 3, 4, 5], values);
1843
 
        });
1844
 
 
1845
 
        list.reset([
1846
 
            {foo: 'item 1', bar: 1},
1847
 
            {foo: 'item 4', bar: 4},
1848
 
            {foo: 'item 3', bar: 3},
1849
 
            {foo: 'item 5', bar: 5},
1850
 
            {foo: 'item 2', bar: 2}
1851
 
        ]);
1852
 
 
1853
 
        Assert.areSame(1, calls);
1854
 
    },
1855
 
 
1856
 
    '`reset` event should be preventable': function () {
1857
 
        var calls = 0,
1858
 
            list  = this.createList();
1859
 
 
1860
 
        list.on('reset', function (e) {
1861
 
            calls += 1;
1862
 
            e.preventDefault();
1863
 
        });
1864
 
 
1865
 
        list.after('reset', function () {
1866
 
            Assert.fail('reset event should be prevented');
1867
 
        });
1868
 
 
1869
 
        list.reset([{}]);
1870
 
 
1871
 
        Assert.areSame(1, calls);
1872
 
        Assert.areSame(0, list.size());
1873
 
    },
1874
 
 
1875
 
    '`reset` event should not fire when the list is reset silently': function () {
1876
 
        var list = this.createList();
1877
 
 
1878
 
        list.on('reset', function () {
1879
 
            Assert.fail('reset event should not fire');
1880
 
        });
1881
 
 
1882
 
        list.reset([{}], {silent: true});
1883
 
 
1884
 
        Assert.areSame(1, list.size());
1885
 
    },
1886
 
 
1887
 
    '`remove` event should fire when a model is removed': function () {
1888
 
        var calls = 0,
1889
 
            list  = this.createList(),
1890
 
            model = list.add({});
1891
 
 
1892
 
        list.once('remove', function (e) {
1893
 
            calls += 1;
1894
 
 
1895
 
            Assert.areSame(model, e.model);
1896
 
            Assert.areSame(0, e.index);
1897
 
            Assert.areSame('test', e.src);
1898
 
        });
1899
 
 
1900
 
        list.remove(model, {src: 'test'});
1901
 
 
1902
 
        list.after('remove', function (e) {
1903
 
            calls += 1;
1904
 
        });
1905
 
 
1906
 
        list.remove(list.add([{}, {}]));
1907
 
 
1908
 
        Assert.areSame(3, calls);
1909
 
    },
1910
 
 
1911
 
    '`remove` event should be preventable': function () {
1912
 
        var calls = 0,
1913
 
            list  = this.createList();
1914
 
 
1915
 
        list.on('remove', function (e) {
1916
 
            calls += 1;
1917
 
            e.preventDefault();
1918
 
        });
1919
 
 
1920
 
        list.after('remove', function () {
1921
 
            Assert.fail('remove event should be prevented');
1922
 
        });
1923
 
 
1924
 
        list.remove(list.add({}));
1925
 
 
1926
 
        Assert.areSame(1, calls);
1927
 
        Assert.areSame(1, list.size());
1928
 
    },
1929
 
 
1930
 
    '`remove` event should not fire when a model is removed silently': function () {
1931
 
        var list = this.createList();
1932
 
 
1933
 
        list.on('remove', function () {
1934
 
            Assert.fail('remove event should not fire');
1935
 
        });
1936
 
 
1937
 
        list.remove(list.add({}), {silent: true});
1938
 
        list.remove(list.add([{}, {}]), {silent: true});
1939
 
 
1940
 
        Assert.areSame(0, list.size());
1941
 
    }
1942
 
}));
1943
 
 
1944
 
// -- View Suite ---------------------------------------------------------------
1945
 
viewSuite = new Y.Test.Suite('View');
1946
 
 
1947
 
// -- View: Lifecycle ----------------------------------------------------------
1948
 
viewSuite.add(new Y.Test.Case({
1949
 
    name: 'Lifecycle',
1950
 
 
1951
 
    'container should be a <div> node by default': function () {
1952
 
        var view = new Y.View();
1953
 
 
1954
 
        Assert.isInstanceOf(Y.Node, view.container);
1955
 
        Assert.areSame('div', view.container.get('tagName').toLowerCase());
1956
 
    },
1957
 
 
1958
 
    'events property should be an empty object by default': function () {
1959
 
        var view = new Y.View();
1960
 
 
1961
 
        Assert.isObject(view.events);
1962
 
        Assert.isTrue(Y.Object.isEmpty(view.events));
1963
 
    },
1964
 
 
1965
 
    'model property should be undefined by default': function () {
1966
 
        Assert.isUndefined(new Y.View().model);
1967
 
    },
1968
 
 
1969
 
    'initializer should allow setting a model reference at init': function () {
1970
 
        var model = new Y.Model(),
1971
 
            view  = new Y.View({model: model});
1972
 
 
1973
 
        Assert.areSame(model, view.model);
1974
 
    },
1975
 
 
1976
 
    'initializer should allow setting a model list reference at init': function () {
1977
 
        var modelList = new Y.ModelList(),
1978
 
            view      = new Y.View({modelList: modelList});
1979
 
 
1980
 
        Assert.areSame(modelList, view.modelList);
1981
 
    },
1982
 
 
1983
 
    'initializer should allow setting a template at init': function () {
1984
 
        var template = {},
1985
 
            view     = new Y.View({template: template});
1986
 
 
1987
 
        Assert.areSame(template, view.template);
1988
 
    },
1989
 
 
1990
 
    'initializer should call create() to create the container node': function () {
1991
 
        var calls = 0,
1992
 
 
1993
 
            TestView = Y.Base.create('testView', Y.View, [], {
1994
 
                create: function (container) {
1995
 
                    calls += 1;
1996
 
                    Assert.areSame('<b/>', container);
1997
 
                }
1998
 
            });
1999
 
 
2000
 
        new TestView({container: '<b/>'});
2001
 
 
2002
 
        Assert.areSame(1, calls);
2003
 
    },
2004
 
 
2005
 
    'initializer should call attachEvents()': function () {
2006
 
        var calls  = 0,
2007
 
            events = {'#foo': {click: 'handler'}},
2008
 
 
2009
 
            TestView = Y.Base.create('testView', Y.View, [], {
2010
 
                events: {'#bar': {click: 'handler'}},
2011
 
 
2012
 
                attachEvents: function (events) {
2013
 
                    calls += 1;
2014
 
 
2015
 
                    Assert.areSame(this.events, events);
2016
 
                    Assert.areSame('handler', events['#foo'].click);
2017
 
                    Assert.areSame('handler', events['#bar'].click);
2018
 
                }
2019
 
            });
2020
 
 
2021
 
        new TestView({events: events});
2022
 
 
2023
 
        Assert.areSame(1, calls);
2024
 
    },
2025
 
 
2026
 
    'destructor should remove the container from the DOM': function () {
2027
 
        var view = new Y.View();
2028
 
 
2029
 
        Y.one('body').append(view.container);
2030
 
        Assert.isTrue(view.container.inDoc());
2031
 
 
2032
 
        view.destroy();
2033
 
        Assert.isNull(view.container._node);
2034
 
    }
2035
 
}));
2036
 
 
2037
 
viewSuite.add(new Y.Test.Case({
2038
 
    name: 'Methods',
2039
 
 
2040
 
    'create() should create and return a container node': function () {
2041
 
        var view = new Y.View(),
2042
 
            node = Y.Node.create('<div/>');
2043
 
 
2044
 
        Assert.areSame(node, view.create(node), "should return the same node if it's already a node");
2045
 
 
2046
 
        node = view.create('<div class="foo"/>');
2047
 
        Assert.isInstanceOf(Y.Node, node);
2048
 
        Assert.areSame('div', node.get('tagName').toLowerCase());
2049
 
        Assert.isTrue(node.hasClass('foo'));
2050
 
 
2051
 
        node = view.create(Y.config.doc.createElement('div'));
2052
 
        Assert.isInstanceOf(Y.Node, node);
2053
 
        Assert.areSame('div', node.get('tagName').toLowerCase());
2054
 
    },
2055
 
 
2056
 
    'remove() should remove the container node from the DOM': function () {
2057
 
        var view = new Y.View();
2058
 
 
2059
 
        Y.one('body').append(view.container);
2060
 
        Assert.isTrue(view.container.inDoc());
2061
 
 
2062
 
        view.remove();
2063
 
        Assert.isFalse(view.container.inDoc());
2064
 
    },
2065
 
 
2066
 
    'render() should be a chainable noop': function () {
2067
 
        var view = new Y.View();
2068
 
        Assert.areSame(view, view.render());
2069
 
    }
2070
 
}));
2071
 
 
2072
 
suite.add(controllerSuite);
2073
 
suite.add(modelSuite);
2074
 
suite.add(modelListSuite);
2075
 
suite.add(viewSuite);
2076
 
 
2077
 
Y.Test.Runner.add(suite);
2078
 
 
2079
 
}, '@VERSION@', {
2080
 
    requires: ['controller', 'model', 'model-list', 'view', 'test']
2081
 
});