1
YUI.add('app-test', function (Y) {
3
var ArrayAssert = Y.ArrayAssert,
5
ObjectAssert = Y.ObjectAssert,
7
html5 = Y.Controller.prototype.html5,
15
// -- Global Suite -------------------------------------------------------------
16
suite = new Y.Test.Suite('App Framework');
18
// -- Controller Suite ---------------------------------------------------------
19
controllerSuite = new Y.Test.Suite({
23
this.oldPath = Y.config.win.location.toString();
26
Y.config.win.location.hash = '';
30
tearDown: function () {
32
Y.config.win.history.replaceState(null, null, this.oldPath);
34
Y.config.win.location.hash = '';
39
// -- Controller: Lifecycle ----------------------------------------------------
40
controllerSuite.add(new Y.Test.Case({
43
tearDown: function () {
44
this.controller && this.controller.destroy();
45
delete this.controller;
48
'initializer should set local `root` and `routes` properties': function () {
49
var controller = this.controller = new Y.Controller({
53
{path: '/', callback: function () {}},
54
{path: '/foo', callback: function () {}}
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);
64
'initializer should create initial routes': function () {
65
var controller = this.controller = new Y.Controller({
67
{path: '/', callback: function () {}},
68
{path: '/foo', callback: function () {}}
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);
78
// -- Controller: Events -------------------------------------------------------
79
controllerSuite.add(new Y.Test.Case({
82
tearDown: function () {
83
this.controller && this.controller.destroy();
84
delete this.controller;
87
'`ready` event should fire when the controller is ready to dispatch': function () {
90
controller = this.controller = new Y.Controller({
93
test.resume(function () {
94
Assert.isFalse(e.dispatched);
103
'`ready` event should set e.dispatched to true if called after dispatch': function () {
106
controller = this.controller = new Y.Controller({
108
initializedChange: function () {
109
this._dispatch('/fake', {});
112
ready: function (e) {
113
test.resume(function () {
114
Assert.isTrue(e.dispatched);
124
// -- Controller: Attributes and Properties ------------------------------------
125
controllerSuite.add(new Y.Test.Case({
126
name: 'Attributes and Properties',
128
tearDown: function () {
129
this.controller && this.controller.destroy();
130
delete this.controller;
133
'`root` property should have a default value': function () {
134
var controller = this.controller = new Y.Controller();
135
Assert.areSame('', controller.root);
138
'`routes` property should have a default value': function () {
139
var controller = this.controller = new Y.Controller();
141
Assert.isArray(controller.routes);
142
ArrayAssert.isEmpty(controller.routes);
146
// -- Controller: Methods ------------------------------------------------------
147
controllerSuite.add(new Y.Test.Case({
150
tearDown: function () {
151
this.controller && this.controller.destroy();
152
delete this.controller;
155
'route() should add a route': function () {
156
var controller = this.controller = new Y.Controller();
158
controller.one = function () {};
161
Assert.areSame(0, controller._routes.length);
163
Assert.areSame(controller, controller.route('/foo', 'one'));
164
Assert.areSame(1, controller._routes.length);
166
controller.route(/bar/, two);
167
Assert.areSame(2, controller._routes.length);
169
Assert.areSame('one', controller._routes[0].callback);
170
Assert.areSame(two, controller._routes[1].callback);
173
'match() should return an array of routes that match the given path': function () {
174
var controller = this.controller = new Y.Controller(),
181
controller.route('/:foo', one);
182
controller.route(/foo/, two);
183
controller.route('/bar', three);
185
routes = controller.match('/foo');
187
Assert.areSame(2, routes.length);
188
Assert.areSame(one, routes[0].callback);
189
Assert.areSame(two, routes[1].callback);
192
'hasRoute() should return `true` if one or more routes match the given path': function () {
193
var controller = this.controller = new Y.Controller(),
198
controller.route('/:foo', noop);
199
controller.route(/foo/, noop);
200
controller.route('/bar', noop);
202
Assert.isTrue(controller.hasRoute('/foo'));
203
Assert.isTrue(controller.hasRoute('/bar'));
204
Assert.isFalse(controller.hasRoute('/baz/quux'));
207
'dispatch() should dispatch to the first route that matches the current URL': function () {
209
controller = this.controller = new Y.Controller();
211
controller.route(/./, function () {
215
setTimeout(function () {
216
controller.dispatch();
222
'dispatch() should upgrade hash URLs to HTML5 URLs in HTML5 browsers': function () {
228
Y.HistoryHash.setHash('/hashpath');
231
controller = this.controller = new Y.Controller();
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');
240
controller.dispatch();
244
'removeRoot() should remove the root URL from a given path': function () {
245
var controller = this.controller = new Y.Controller();
247
controller.root = '/';
248
Assert.areSame('/bar', controller.removeRoot('/bar'));
249
Assert.areSame('/bar', controller.removeRoot('bar'));
251
controller.root = '/foo';
252
Assert.areSame('/bar', controller.removeRoot('/foo/bar'));
254
controller.root = '/foo/';
255
Assert.areSame('/bar', controller.removeRoot('/foo/bar'));
257
controller.root = '/moo';
258
Assert.areSame('/foo/bar', controller.removeRoot('/foo/bar'));
261
'removeRoot() should strip the "http://foo.com" portion of the URL, if any': function () {
262
var controller = this.controller = new Y.Controller();
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'));
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'));
278
'replace() should replace the current history entry': function () {
280
controller = this.controller = new Y.Controller();
282
controller.route('/replace', function (req) {
283
test.resume(function () {
284
Assert.areSame('/replace', req.path);
285
Assert.isObject(req.query);
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');
298
'save() should create a new history entry': function () {
300
controller = this.controller = new Y.Controller();
302
controller.route('/save', function (req) {
303
test.resume(function () {
304
Assert.areSame('/save', req.path);
305
Assert.isObject(req.query);
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');
318
'consecutive save() calls should dispatch to the correct routes': function () {
321
controller = this.controller = new Y.Controller();
323
controller.route('/one', function (req) {
324
paths.push(req.path);
327
controller.route('/two', function (req) {
328
paths.push(req.path);
331
controller.route('/three', function (req) {
332
paths.push(req.path);
334
test.resume(function () {
335
ArrayAssert.itemsAreSame(['/one', '/two', '/three'], paths);
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');
350
'_joinURL() should normalize / separators': function () {
351
var controller = this.controller = new Y.Controller();
353
controller.root = '/foo';
354
Assert.areSame('/foo/bar', controller._joinURL('bar'));
355
Assert.areSame('/foo/bar', controller._joinURL('/bar'));
357
controller.root = '/foo/';
358
Assert.areSame('/foo/bar', controller._joinURL('bar'));
359
Assert.areSame('/foo/bar', controller._joinURL('/bar'));
363
// -- Controller: Routes -------------------------------------------------------
364
controllerSuite.add(new Y.Test.Case({
367
tearDown: function () {
368
this.controller && this.controller.destroy();
369
delete this.controller;
372
'routes should be called in the context of the controller': function () {
374
controller = this.controller = new Y.Controller({
375
routes: [{path: '/foo', callback: 'foo'}]
378
controller.foo = function () {
380
Assert.areSame(controller, this);
383
controller.route('/bar', controller.foo);
385
controller._dispatch('/foo', {});
386
controller._dispatch('/bar', {});
388
Assert.areSame(2, calls);
391
'routes should receive a request object and `next` function as params': function () {
393
controller = this.controller = new Y.Controller();
395
controller.route('/foo', function (req, next) {
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);
407
// Duckpunching _getQuery so we can test req.query.
408
controller._getQuery = function () {
409
return 'bar=baz%20quux&moo';
412
controller._dispatch('/foo', {foo: 'foo'});
414
Assert.areSame(1, calls);
417
'request object should contain captured route parameters': function () {
419
controller = this.controller = new Y.Controller();
421
controller.route('/foo/:bar/:baz', function (req) {
424
ArrayAssert.itemsAreSame(['bar', 'baz'], Y.Object.keys(req.params));
425
ArrayAssert.itemsAreSame(['one', 'two'], Y.Object.values(req.params));
428
controller.route('/bar/*path', function (req) {
431
Assert.isObject(req.params);
432
ArrayAssert.itemsAreSame(['path'], Y.Object.keys(req.params));
433
ArrayAssert.itemsAreSame(['one/two'], Y.Object.values(req.params));
436
controller.route(/^\/(baz)\/(quux)$/, function (req) {
439
Assert.isArray(req.params);
440
ArrayAssert.itemsAreSame(['/baz/quux', 'baz', 'quux'], req.params);
443
controller._dispatch('/foo/one/two', {});
444
controller._dispatch('/bar/one/two', {});
445
controller._dispatch('/baz/quux', {});
447
Assert.areSame(3, calls);
450
'calling `next()` should pass control to the next matching route': function () {
452
controller = this.controller = new Y.Controller();
454
controller.route('/foo', function (req, next) {
459
controller.route(/foo/, function (req, next) {
464
controller.route('/foo', function (req, next) {
468
controller.route('/foo', function (req, next) {
470
Assert.fail('final route should not be called');
473
controller._dispatch('/foo', {});
475
Assert.areSame(3, calls);
479
// -- Model Suite --------------------------------------------------------------
480
modelSuite = new Y.Test.Suite('Model');
482
// -- Model: Lifecycle ---------------------------------------------------------
483
modelSuite.add(new Y.Test.Case({
486
'destroy() should destroy the model instance': function () {
487
var model = new Y.Model();
489
model.sync = function () {
490
Assert.fail('sync should not be called unless the model is being deleted');
493
Assert.isFalse(model.get('destroyed'));
494
Assert.areSame(model, model.destroy(), 'destroy() should be chainable');
495
Assert.isTrue(model.get('destroyed'));
498
'destroy() should call a callback if provided as the only arg': function () {
500
model = new Y.Model();
502
Y.Mock.expect(mock, {
507
model.destroy(mock.callback);
511
'destroy() should call a callback if provided as the second arg': function () {
513
model = new Y.Model();
515
Y.Mock.expect(mock, {
520
model.destroy({}, mock.callback);
524
'destroy() should delete the model if the `delete` option is truthy': function () {
527
model = new Y.Model();
529
Y.Mock.expect(mock, {
534
model.sync = function (action, options, callback) {
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');
545
model.destroy({'delete': true}, mock.callback);
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();
557
listThree.add(model);
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');
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');
571
// -- Model: Attributes and Properties -----------------------------------------
572
modelSuite.add(new Y.Test.Case({
573
name: 'Attributes and Properties',
576
this.TestModel = Y.Base.create('testModel', Y.Model, [], {
577
idAttribute: 'customId'
580
customId: {value: ''},
586
tearDown: function () {
587
delete this.TestModel;
590
'Attributes should be settable at instantiation time': function () {
591
var model = new this.TestModel({foo: 'foo'});
592
Assert.areSame('foo', model.get('foo'));
595
'Custom id attribute should be settable at instantiation time': function () {
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
602
model = new this.TestModel({customId: 'foo'});
603
Assert.areSame('foo', model.get('customId'));
604
Assert.areSame('foo', model.get('id'));
606
model = new this.TestModel({customId: 'foo'});
607
Assert.areSame('foo', model.get('id'));
608
Assert.areSame('foo', model.get('customId'));
610
model = new this.TestModel({id: 'foo'});
611
Assert.areSame('foo', model.get('customId'));
612
Assert.areSame('foo', model.get('id'));
614
model = new this.TestModel({id: 'foo'});
615
Assert.areSame('foo', model.get('id'));
616
Assert.areSame('foo', model.get('customId'));
619
'`id` attribute should be an alias for the custom id attribute': function () {
621
model = new this.TestModel();
623
model.on('change', function (e) {
626
Assert.areSame('foo', e.changed.customId.newVal);
627
Assert.areSame('foo', e.changed.id.newVal);
630
model.set('id', 'foo');
632
Assert.areSame(1, calls);
635
'`changed` property should be a hash of attributes that have changed since last save() or load()': function () {
636
var model = new this.TestModel();
638
Assert.isObject(model.changed);
639
ObjectAssert.ownsNoKeys(model.changed);
641
model.set('foo', 'foo');
642
Assert.areSame('foo', model.changed.foo);
644
model.setAttrs({foo: 'bar', bar: 'baz'});
645
ObjectAssert.areEqual({foo: 'bar', bar: 'baz'}, model.changed);
648
ObjectAssert.ownsNoKeys(model.changed);
650
model.set('foo', 'foo');
652
ObjectAssert.ownsNoKeys(model.changed);
655
'clientId attribute should be automatically generated': function () {
656
var model = new Y.Model();
658
Assert.isString(model.get('clientId'));
659
Assert.isTrue(!!model.get('clientId'));
662
'`lastChange` property should contain attributes that changed in the last `change` event': function () {
663
var model = new this.TestModel();
665
Assert.isObject(model.lastChange);
666
ObjectAssert.ownsNoKeys(model.lastChange);
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);
675
model.set('bar', 'bar', {src: 'test'});
676
Assert.areSame(1, Y.Object.size(model.lastChange));
677
Assert.areSame('test', model.lastChange.bar.src);
679
model.set('foo', 'bar', {silent: true});
680
Assert.areSame(1, Y.Object.size(model.lastChange));
681
Assert.areSame('bar', model.lastChange.foo.newVal);
684
'`lists` property should be an array of ModelList instances that contain this model': function () {
686
model = new this.TestModel(),
689
new Y.ModelList({model: this.TestModel}),
690
new Y.ModelList({model: this.TestModel})
693
Assert.isArray(model.lists);
695
function onChange() {
699
lists[0].on('*:change', onChange);
700
lists[1].on('*:change', onChange);
705
ArrayAssert.itemsAreSame(lists, model.lists);
707
model.set('foo', 'foo');
709
Assert.areSame(2, calls);
713
// -- Model: Methods -----------------------------------------------------------
714
modelSuite.add(new Y.Test.Case({
718
this.TestModel = Y.Base.create('testModel', Y.Model, [], {}, {
726
tearDown: function () {
727
delete this.TestModel;
730
'generateClientId() should generate a unique client id': function () {
731
var model = new this.TestModel(),
732
firstId = model.generateClientId(),
733
secondId = model.generateClientId();
735
Assert.isString(firstId);
736
Assert.areNotSame(firstId, secondId);
737
Assert.isTrue(firstId.indexOf(this.TestModel.NAME) === 0);
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});
744
Assert.areSame(Y.Escape.html(value), model.getAsHTML('foo'));
747
'getAsURL() should return a URL-encoded attribute value': function () {
748
var value = 'foo & bar = baz',
749
model = new this.TestModel({foo: value});
751
Assert.areSame(encodeURIComponent(value), model.getAsURL('foo'));
754
'isModified() should return true if the model is new': function () {
755
var model = new this.TestModel();
756
Assert.isTrue(model.isModified());
758
model = new this.TestModel({id: 'foo'});
759
Assert.isFalse(model.isModified());
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());
766
model.set('foo', 'bar');
767
Assert.isTrue(model.isModified());
770
Assert.isFalse(model.isModified());
773
'isNew() should return true if the model is new': function () {
774
var model = new this.TestModel();
775
Assert.isTrue(model.isNew());
777
model = new this.TestModel({id: 'foo'});
778
Assert.isFalse(model.isNew());
780
model = new this.TestModel({id: 0});
781
Assert.isFalse(model.isNew());
784
'load() should delegate to sync()': function () {
786
model = new this.TestModel(),
789
model.sync = function (action, options, callback) {
792
Assert.areSame('read', action);
793
Assert.areSame(opts, options);
794
Assert.isFunction(callback);
800
Assert.areSame(1, calls);
803
'load() should reset this.changed when loading succeeds': function () {
804
var model = new this.TestModel();
806
model.set('foo', 'bar');
807
Assert.areSame(1, Y.Object.size(model.changed));
810
Assert.areSame(0, Y.Object.size(model.changed));
813
'load() should be chainable and should call the callback if one was provided': function () {
815
model = new this.TestModel();
817
Assert.areSame(model, model.load());
818
Assert.areSame(model, model.load({}));
820
Assert.areSame(model, model.load(function (err) {
822
Assert.isUndefined(err);
825
Assert.areSame(model, model.load({}, function () {
829
Assert.areSame(2, calls);
832
'parse() should parse a JSON string and return an object': function () {
833
var model = new this.TestModel(),
834
response = model.parse('{"foo": "bar"}');
836
Assert.isObject(response);
837
Assert.areSame('bar', response.foo);
840
'parse() should not try to parse non-strings': function () {
841
var model = new this.TestModel(),
842
array = ['foo', 'bar'],
843
object = {foo: 'bar'};
845
Assert.areSame(array, model.parse(array));
846
Assert.areSame(object, model.parse(object));
849
'save() should delegate to sync()': function () {
851
model = new this.TestModel(),
854
model.sync = function (action, options, callback) {
857
Assert.areSame('create', action);
858
Assert.areSame(opts, options);
859
Assert.isFunction(callback);
861
// Give the model an id so it will no longer be new.
862
callback(null, {id: 'foo'});
867
Assert.areSame('foo', model.get('id'), "model id should be updated after save");
869
model.sync = function (action) {
871
Assert.areSame('update', action);
876
Assert.areSame(2, calls);
879
'save() should reset this.changed when saving succeeds': function () {
880
var model = new this.TestModel();
882
model.set('foo', 'bar');
883
Assert.areSame(1, Y.Object.size(model.changed));
886
Assert.areSame(0, Y.Object.size(model.changed));
889
'save() should be chainable and should call the callback if one was provided': function () {
891
model = new this.TestModel();
893
Assert.areSame(model, model.save());
894
Assert.areSame(model, model.save({}));
896
Assert.areSame(model, model.save(function (err) {
898
Assert.isUndefined(err);
901
Assert.areSame(model, model.save({}, function () {
905
Assert.areSame(2, calls);
908
'set() should set the value of a single attribute': function () {
909
var model = new this.TestModel();
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'));
916
'setAttrs() should set the values of multiple attributes': function () {
917
var model = new this.TestModel();
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'));
926
'sync() should just call the supplied callback by default': function () {
928
model = new this.TestModel();
930
model.sync(function (err) {
932
Assert.isUndefined(err);
935
Assert.areSame(1, calls);
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;
943
json = model.toJSON();
944
Assert.areSame(3, Y.Object.size(json));
945
ObjectAssert.ownsKeys(['id', 'foo', 'bar'], json);
946
ObjectAssert.areEqual(attrs, json);
948
// When there's a custom id attribute, the 'id' attribute should be
950
CustomTestModel = Y.Base.create('customTestModel', Y.Model, [], {
951
idAttribute: 'customId'
954
customId: {value: ''},
960
attrs = {customId: 'id', foo: 'foo', bar: 'bar'};
961
model = new CustomTestModel(attrs);
962
json = model.toJSON();
964
Assert.areSame(3, Y.Object.size(json));
965
ObjectAssert.ownsKeys(['customId', 'foo', 'bar'], json);
966
ObjectAssert.areEqual(attrs, json);
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);
973
ObjectAssert.areEqual(attrs, model.toJSON());
975
model.setAttrs({foo: 'moo', bar: 'quux'});
976
ObjectAssert.areEqual({id: 'id', foo: 'moo', bar: 'quux'}, model.toJSON());
978
Assert.areSame(model, model.undo(), 'undo() should be chainable');
979
ObjectAssert.areEqual(attrs, model.toJSON());
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'});
985
model.setAttrs({foo: 'moo', bar: 'quux'});
988
ObjectAssert.areEqual({id: 'id', foo: 'foo', bar: 'quux'}, model.toJSON());
991
'undo() should pass options to setAttrs()': function () {
993
model = new this.TestModel({id: 'id', foo: 'foo', bar: 'bar'});
995
model.setAttrs({foo: 'moo', bar: 'quux'});
997
model.on('change', function (e) {
999
Assert.areSame('test', e.changed.foo.src);
1002
model.undo(null, {src: 'test'});
1003
Assert.areSame(1, calls);
1006
'undo() should do nothing when there is no previous change to revert': function () {
1007
var model = new this.TestModel();
1009
model.on('change', function () {
1010
Assert.fail('`change` should not be called');
1016
'validate() should be a noop function by default': function () {
1017
var model = new this.TestModel();
1019
Assert.isFunction(model.validate);
1020
Assert.isUndefined(model.validate());
1023
'validate() should only be called on save()': function () {
1025
model = new this.TestModel();
1027
model.validate = function (attrs) {
1029
Y.ObjectAssert.areEqual(model.toJSON(), attrs);
1032
model.set('foo', 'bar');
1033
model.set('foo', 'baz');
1036
Assert.areSame(1, calls);
1039
'a validation failure should abort a save() call': function () {
1042
model = new this.TestModel(),
1045
model.validate = function (attrs) {
1047
return 'OMG invalid!';
1050
model.sync = function () {
1051
Assert.fail('sync() should not be called on validation failure');
1054
model.on('error', function (e) {
1056
Assert.areSame('OMG invalid!', e.error);
1057
Assert.areSame('validate', e.src);
1060
model.save(function (err, res) {
1062
Assert.areSame('OMG invalid!', err);
1063
Assert.isUndefined(res);
1066
Assert.areSame(1, calls);
1067
Assert.areSame(1, saveCallbacks);
1068
Assert.areSame(1, errors);
1072
// -- Model: Events ------------------------------------------------------------
1073
modelSuite.add(new Y.Test.Case({
1076
setUp: function () {
1077
this.TestModel = Y.Base.create('testModel', Y.Model, [], {}, {
1086
tearDown: function () {
1087
delete this.TestModel;
1090
'`change` event should contain coalesced attribute changes': function () {
1092
model = new this.TestModel();
1094
model.on('change', function (e) {
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);
1114
Assert.areSame(1, calls);
1117
'`change` event should not fire when the _silent_ option is truthy': function () {
1118
var model = new this.TestModel();
1120
model.on('change', function (e) {
1121
Assert.fail('`change` should not fire');
1124
model.set('foo', 'bar', {silent: true});
1125
model.setAttrs({bar: 'baz'}, {silent: true});
1128
'`error` event should fire when validation fails': function () {
1130
model = new this.TestModel();
1132
model.validate = function (hash) {
1133
return 'ERROR. ERROR. DOES NOT COMPUTE.';
1136
model.on('error', function (e) {
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);
1145
model.set('foo', 'bar');
1148
Assert.areSame(1, calls);
1151
'`error` event should fire when parsing fails': function () {
1153
model = new this.TestModel();
1155
model.on('error', function (e) {
1158
Assert.areSame('parse', e.src);
1159
Y.assert(e.error instanceof Error);
1160
Assert.areSame('moo', e.response);
1165
Assert.areSame(1, calls);
1169
// -- ModelList Suite ----------------------------------------------------------
1170
modelListSuite = new Y.Test.Suite('ModelList');
1172
// -- ModelList: Lifecycle -----------------------------------------------------
1173
modelListSuite.add(new Y.Test.Case({
1176
setUp: function () {
1177
this.list = new Y.ModelList({model: Y.Model});
1180
tearDown: function () {
1184
'ModelLists should have a `model` property': function () {
1185
Assert.isNull(new Y.ModelList().model);
1188
'destructor should detach all models from the list': function () {
1189
var model = new Y.Model();
1191
this.list.add(model);
1192
Assert.areSame(this.list, model.lists[0]);
1194
this.list.destroy();
1195
ArrayAssert.isEmpty(model.lists);
1199
// -- ModelList: Methods -------------------------------------------------------
1200
modelListSuite.add(new Y.Test.Case({
1203
setUp: function () {
1204
this.TestModel = Y.Base.create('testModel', Y.Model, [], {}, {
1211
this.TestList = Y.Base.create('testList', Y.ModelList, []);
1213
this.createList = function (modelClass) {
1214
return new this.TestList({model: modelClass || this.TestModel});
1217
this.createModel = function (config) {
1218
return new this.TestModel(config);
1222
tearDown: function () {
1223
delete this.createList;
1224
delete this.createModel;
1225
delete this.TestList;
1226
delete this.TestModel;
1229
'add() should add a model to the list': function () {
1230
var list = this.createList(),
1231
model = this.createModel(),
1234
Assert.areSame(model, list.add(model));
1235
Assert.areSame(1, list.size());
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'));
1243
'add() should add an array of models to the list': function () {
1244
var list = this.createList(),
1245
models = [this.createModel(), this.createModel()],
1248
ArrayAssert.itemsAreSame(models, list.add(models));
1249
Assert.areSame(2, list.size());
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'));
1259
'comparator() should be undefined by default': function () {
1260
Assert.isUndefined(this.createList().comparator);
1263
'models should be added in the proper position based on the comparator': function () {
1264
var list = this.createList();
1266
list.comparator = function (model) {
1267
return model.get('foo');
1270
list.add([{foo: 'z'}, {foo: 'a'}, {foo: 'x'}, {foo: 'y'}]);
1272
ArrayAssert.itemsAreSame(['a', 'x', 'y', 'z'], list.get('foo'));
1275
'create() should create or update a model, then add it to the list': function () {
1276
var list = this.createList(),
1277
model = this.createModel();
1279
Assert.areSame(model, list.create(model));
1280
Assert.areSame(1, list.size());
1282
Assert.isInstanceOf(this.TestModel, list.create({foo: 'foo'}));
1283
Assert.areSame(2, list.size());
1286
'create() should call the callback if one is provided': function () {
1288
list = this.createList();
1290
list.create({}, {}, function (err) {
1292
Assert.isUndefined(err);
1295
list.create({}, function () { calls += 1; });
1297
Assert.areSame(2, calls);
1300
'create() should pass an error to the callback if one occurs': function () {
1302
list = this.createList(),
1303
model = this.createModel();
1305
model.sync = function (action, options, callback) {
1306
callback('Oh noes!');
1309
list.create(model, function (err) {
1311
Assert.areSame('Oh noes!', err);
1314
Assert.areSame(1, calls);
1317
'get() should return an array of attribute values from all models in the list': function () {
1318
var list = this.createList();
1320
list.add([{foo: 'one'}, {foo: 'two'}]);
1321
ArrayAssert.itemsAreSame(['one', 'two'], list.get('foo'));
1324
'get() should return a list attribute if there is one': function () {
1325
var list = this.createList();
1327
list.addAttr('foo', {value: '<listfoo>'});
1328
list.add([{foo: 'modelfoo-one'}, {foo: 'modelfoo-two'}]);
1330
Assert.areSame('<listfoo>', list.get('foo'));
1333
'getAsHTML() should return an array of HTML-escaped attribute values': function () {
1334
var list = this.createList();
1336
list.add([{foo: '<foo>'}, {foo: '<bar>'}]);
1337
ArrayAssert.itemsAreSame(['<foo>', '<bar>'], list.getAsHTML('foo'));
1340
'getAsHTML() should return a list attribute if there is one': function () {
1341
var list = this.createList();
1343
list.addAttr('foo', {value: '<listfoo>'});
1344
list.add([{foo: 'modelfoo-one'}, {foo: 'modelfoo-two'}]);
1346
Assert.areSame('<listfoo>', list.getAsHTML('foo'));
1349
'getAsURL() should return an array of URL-encoded attribute values': function () {
1350
var list = this.createList();
1352
list.add([{foo: 'a b'}, {foo: 'c d'}]);
1353
ArrayAssert.itemsAreSame(['a%20b', 'c%20d'], list.getAsURL('foo'));
1356
'getAsURL() should return a list attribute if there is one': function () {
1357
var list = this.createList();
1359
list.addAttr('foo', {value: 'list foo'});
1360
list.add([{foo: 'modelfoo-one'}, {foo: 'modelfoo-two'}]);
1362
Assert.areSame('list%20foo', list.getAsURL('foo'));
1365
'getByClientId() should look up a model by its clientId': function () {
1366
var list = this.createList(),
1367
model = list.add({});
1369
Assert.areSame(model, list.getByClientId(model.get('clientId')));
1370
Assert.isNull(list.getByClientId('bogus'));
1373
'getById() should look up a model by its id': function () {
1374
var list = this.createList(),
1375
model = list.add({id: 'foo'});
1377
Assert.areSame(model, list.getById(model.get('id')));
1378
Assert.isNull(list.getById('bogus'));
1381
'getById() should work with numeric ids': function () {
1382
var list = this.createList(),
1383
model = list.add({id: 0});
1385
Assert.areSame(model, list.getById(0));
1388
'getById() should work with custom ids': function () {
1389
var CustomModel = Y.Base.create('customModel', Y.Model, [], {
1390
idAttribute: 'customId'
1393
customId: {value: ''}
1397
list = this.createList(CustomModel),
1398
model = list.add({customId: 'foo'});
1400
Assert.areSame(model, list.getById(model.get('customId')));
1403
'invoke() should call the named method on every model in the list': function () {
1404
var list = this.createList(),
1408
results = list.invoke('set', 'foo', 'foo');
1410
ArrayAssert.itemsAreSame(list.toArray(), results, 'invoke should return an array of return values');
1411
ArrayAssert.itemsAreSame(['foo', 'foo'], list.get('foo'));
1414
'item() should return the model at the specified index': function () {
1415
var list = this.createList();
1417
list.add([{foo: 'zero'}, {foo: 'one'}]);
1419
Assert.areSame('zero', list.item(0).get('foo'));
1420
Assert.areSame('one', list.item(1).get('foo'));
1423
'load() should delegate to sync()': function () {
1425
list = this.createList(),
1428
list.sync = function (action, options, callback) {
1431
Assert.areSame('read', action);
1432
Assert.areSame(opts, options);
1433
Assert.isFunction(callback);
1439
Assert.areSame(1, calls);
1442
'load() should be chainable and should call the callback if one was provided': function () {
1444
list = this.createList();
1446
Assert.areSame(list, list.load());
1447
Assert.areSame(list, list.load({}));
1449
Assert.areSame(list, list.load(function (err) {
1451
Assert.isUndefined(err);
1454
Assert.areSame(list, list.load({}, function () {
1458
Assert.areSame(2, calls);
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(),
1466
list.add([{foo: 'zero'}, {foo: 'one'}]);
1468
results = list.map(function (model) {
1469
Assert.areSame(obj, this);
1470
return model.get('foo');
1473
ArrayAssert.itemsAreSame(['zero', 'one'], results);
1476
'parse() should parse a JSON string and return an object': function () {
1477
var list = this.createList(),
1478
response = list.parse('[{"foo": "bar"}]');
1480
Assert.isArray(response);
1481
Assert.areSame('bar', response[0].foo);
1484
'parse() should not try to parse non-strings': function () {
1485
var list = this.createList(),
1486
array = ['foo', 'bar'],
1487
object = {foo: 'bar'};
1489
Assert.areSame(array, list.parse(array));
1490
Assert.areSame(object, list.parse(object));
1493
'reset() should replace all models in the list': function () {
1494
var list = this.createList(),
1495
models = list.add([{foo: 'zero'}, {foo: 'one'}]);
1497
Assert.areSame(list, list.reset([{foo: 'two'}, {foo: 'three'}]));
1498
ArrayAssert.itemsAreSame(['two', 'three'], list.get('foo'));
1500
// Removed models should be cleanly detached.
1501
Assert.isUndefined(models[0].list);
1502
Assert.isUndefined(models[1].list);
1504
// And we should be able to re-add them.
1506
ArrayAssert.itemsAreSame(['zero', 'one'], list.get('foo'));
1509
'reset() should sort the new models in the list': function () {
1510
var list = this.createList();
1512
list.comparator = function (model) {
1513
return model.get('bar');
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}
1524
ArrayAssert.itemsAreSame([1, 2, 3, 4, 5], list.get('bar'));
1527
'reset() with no args should clear the list': function () {
1528
var list = this.createList(),
1529
models = list.add([{foo: 'zero'}, {foo: 'one'}]);
1531
Assert.areSame(2, list.size());
1533
Assert.areSame(0, list.size());
1536
'remove() should remove a single model from the list': function () {
1537
var list = this.createList();
1539
list.add([{foo: 'zero'}, {foo: 'one'}]);
1541
Assert.areSame('zero', list.remove(list.item(0)).get('foo'));
1542
Assert.areSame(1, list.size());
1545
'remove() should remove an array of models from the list': function () {
1546
var list = this.createList(),
1549
list.add([{foo: 'zero'}, {foo: 'one'}]);
1550
removed = list.remove([list.item(0), list.item(1)]);
1552
Assert.areSame('zero', removed[0].get('foo'));
1553
Assert.areSame('one', removed[1].get('foo'));
1554
Assert.areSame(0, list.size());
1557
// 'set() should set a single attribute value on all models in the list': function () {
1561
// 'setAttrs() should set multiple attribute values on all models in the list': function () {
1565
'sort() should re-sort the list': function () {
1566
var list = this.createList();
1568
list.add([{foo: 'z'}, {foo: 'a'}, {foo: 'x'}, {foo: 'y'}]);
1570
ArrayAssert.itemsAreSame(['z', 'a', 'x', 'y'], list.get('foo'));
1572
list.comparator = function (model) {
1573
return model.get('foo');
1576
Assert.areSame(list, list.sort(), 'sort() should be chainable');
1577
ArrayAssert.itemsAreSame(['a', 'x', 'y', 'z'], list.get('foo'));
1581
'sync() should just call the supplied callback by default': function () {
1583
list = this.createList();
1585
list.sync(function (err) {
1587
Assert.isUndefined(err);
1590
Assert.areSame(1, calls);
1593
'toArray() should return an array containing all the models in the list': function () {
1594
var list = this.createList(),
1595
models = list.add([{}, {}]);
1597
ArrayAssert.itemsAreSame(models, list.toArray());
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();
1605
Assert.isArray(json);
1606
ObjectAssert.areEqual(models[0].toJSON(), json[0]);
1607
ObjectAssert.areEqual(models[1].toJSON(), json[1]);
1611
// -- ModelList: Events --------------------------------------------------------
1612
modelListSuite.add(new Y.Test.Case({
1615
setUp: function () {
1616
this.TestModel = Y.Base.create('testModel', Y.Model, [], {}, {
1623
this.TestList = Y.Base.create('testList', Y.ModelList, []);
1625
this.createList = function (modelClass) {
1626
return new this.TestList({model: modelClass || this.TestModel});
1629
this.createModel = function (config) {
1630
return new this.TestModel(config);
1634
tearDown: function () {
1635
delete this.createList;
1636
delete this.createModel;
1637
delete this.TestList;
1638
delete this.TestModel;
1641
'`add` event should fire when a model is added': function () {
1643
list = this.createList(),
1644
model = this.createModel();
1646
list.once('add', function (e) {
1649
Assert.areSame(model, e.model);
1650
Assert.areSame(0, e.index);
1651
Assert.areSame('test', e.src);
1654
list.add(model, {src: 'test'});
1656
list.after('add', function (e) {
1662
Assert.areSame(3, calls);
1665
'`add` event should be preventable': function () {
1667
list = this.createList();
1669
list.on('add', function (e) {
1674
list.after('add', function () {
1675
Assert.fail('add event should be prevented');
1680
Assert.areSame(1, calls);
1681
Assert.areSame(0, list.size());
1684
'`add` event should not fire when a model is added silently': function () {
1685
var list = this.createList();
1687
list.on('add', function () {
1688
Assert.fail('add event should not fire');
1691
list.add({}, {silent: true});
1692
list.add([{}, {}], {silent: true});
1694
Assert.areSame(3, list.size());
1697
'`change` event should bubble up from models': function () {
1699
list = this.createList(),
1700
model = list.add({});
1702
list.on('*:change', function (e) {
1705
Assert.areSame(model, e.target);
1706
Assert.areSame(list, e.currentTarget);
1709
model.set('foo', 'foo').set('bar', 'bar');
1711
Assert.areSame(2, calls);
1714
'`error` event should bubble up from models': function () {
1716
list = this.createList(),
1717
model = list.add({});
1719
model.validate = function (hash) {
1720
if (hash.foo === 'invalid') {
1725
list.on('*:error', function (e) {
1728
Assert.areSame(model, e.target);
1729
Assert.areSame(list, e.currentTarget);
1732
model.set('foo', 'invalid');
1735
Assert.areSame(1, calls);
1738
'`error` event should fire when a duplicate model is added': function () {
1740
list = this.createList(),
1741
model = this.createModel();
1743
list.on('error', function (e) {
1746
Assert.areSame(model, e.model);
1747
Assert.areSame('add', e.src);
1751
list.add(model, {src: 'test'});
1754
Assert.areSame(1, calls);
1757
"`error` event should fire when a model that isn't in the list is removed": function () {
1759
list = this.createList(),
1760
model = this.createModel();
1762
list.on('error', function (e) {
1765
Assert.areSame(model, e.model);
1766
Assert.areSame('remove', e.src);
1771
list.remove(model, {src: 'test'});
1773
Assert.areSame(1, calls);
1776
"`error` event should fire when a sync layer response can't be parsed": function () {
1778
list = this.createList(),
1779
response = 'foo bar baz';
1781
list.once('error', function (e) {
1784
Assert.areSame(response, e.response);
1785
Assert.areSame('parse', e.src);
1788
list.parse(response);
1789
list.parse('{"foo": "bar"}');
1791
Assert.areSame(1, calls);
1794
'`reset` event should fire when the list is reset or sorted': function () {
1796
list = this.createList(),
1797
models = [this.createModel(), this.createModel()];
1799
list.once('reset', function (e) {
1802
ArrayAssert.itemsAreSame(models, e.models);
1803
Assert.areSame('reset', e.src);
1804
Assert.areSame('test', e.test);
1807
list.reset(models, {test: 'test'});
1809
list.after('reset', function (e) {
1812
Assert.areSame('sort', e.src);
1813
Assert.areSame('test', e.test);
1816
list.comparator = function (model) {
1817
return model.get('clientId');
1820
list.sort({test: 'test'});
1822
Assert.areSame(2, calls);
1825
'`reset` event facade should contain sorted models': function () {
1827
list = this.createList();
1829
list.comparator = function (model) {
1830
return model.get('bar');
1833
list.once('reset', function (e) {
1838
Y.Array.each(e.models, function (model) {
1839
values.push(model.get('bar'));
1842
ArrayAssert.itemsAreSame([1, 2, 3, 4, 5], values);
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}
1853
Assert.areSame(1, calls);
1856
'`reset` event should be preventable': function () {
1858
list = this.createList();
1860
list.on('reset', function (e) {
1865
list.after('reset', function () {
1866
Assert.fail('reset event should be prevented');
1871
Assert.areSame(1, calls);
1872
Assert.areSame(0, list.size());
1875
'`reset` event should not fire when the list is reset silently': function () {
1876
var list = this.createList();
1878
list.on('reset', function () {
1879
Assert.fail('reset event should not fire');
1882
list.reset([{}], {silent: true});
1884
Assert.areSame(1, list.size());
1887
'`remove` event should fire when a model is removed': function () {
1889
list = this.createList(),
1890
model = list.add({});
1892
list.once('remove', function (e) {
1895
Assert.areSame(model, e.model);
1896
Assert.areSame(0, e.index);
1897
Assert.areSame('test', e.src);
1900
list.remove(model, {src: 'test'});
1902
list.after('remove', function (e) {
1906
list.remove(list.add([{}, {}]));
1908
Assert.areSame(3, calls);
1911
'`remove` event should be preventable': function () {
1913
list = this.createList();
1915
list.on('remove', function (e) {
1920
list.after('remove', function () {
1921
Assert.fail('remove event should be prevented');
1924
list.remove(list.add({}));
1926
Assert.areSame(1, calls);
1927
Assert.areSame(1, list.size());
1930
'`remove` event should not fire when a model is removed silently': function () {
1931
var list = this.createList();
1933
list.on('remove', function () {
1934
Assert.fail('remove event should not fire');
1937
list.remove(list.add({}), {silent: true});
1938
list.remove(list.add([{}, {}]), {silent: true});
1940
Assert.areSame(0, list.size());
1944
// -- View Suite ---------------------------------------------------------------
1945
viewSuite = new Y.Test.Suite('View');
1947
// -- View: Lifecycle ----------------------------------------------------------
1948
viewSuite.add(new Y.Test.Case({
1951
'container should be a <div> node by default': function () {
1952
var view = new Y.View();
1954
Assert.isInstanceOf(Y.Node, view.container);
1955
Assert.areSame('div', view.container.get('tagName').toLowerCase());
1958
'events property should be an empty object by default': function () {
1959
var view = new Y.View();
1961
Assert.isObject(view.events);
1962
Assert.isTrue(Y.Object.isEmpty(view.events));
1965
'model property should be undefined by default': function () {
1966
Assert.isUndefined(new Y.View().model);
1969
'initializer should allow setting a model reference at init': function () {
1970
var model = new Y.Model(),
1971
view = new Y.View({model: model});
1973
Assert.areSame(model, view.model);
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});
1980
Assert.areSame(modelList, view.modelList);
1983
'initializer should allow setting a template at init': function () {
1985
view = new Y.View({template: template});
1987
Assert.areSame(template, view.template);
1990
'initializer should call create() to create the container node': function () {
1993
TestView = Y.Base.create('testView', Y.View, [], {
1994
create: function (container) {
1996
Assert.areSame('<b/>', container);
2000
new TestView({container: '<b/>'});
2002
Assert.areSame(1, calls);
2005
'initializer should call attachEvents()': function () {
2007
events = {'#foo': {click: 'handler'}},
2009
TestView = Y.Base.create('testView', Y.View, [], {
2010
events: {'#bar': {click: 'handler'}},
2012
attachEvents: function (events) {
2015
Assert.areSame(this.events, events);
2016
Assert.areSame('handler', events['#foo'].click);
2017
Assert.areSame('handler', events['#bar'].click);
2021
new TestView({events: events});
2023
Assert.areSame(1, calls);
2026
'destructor should remove the container from the DOM': function () {
2027
var view = new Y.View();
2029
Y.one('body').append(view.container);
2030
Assert.isTrue(view.container.inDoc());
2033
Assert.isNull(view.container._node);
2037
viewSuite.add(new Y.Test.Case({
2040
'create() should create and return a container node': function () {
2041
var view = new Y.View(),
2042
node = Y.Node.create('<div/>');
2044
Assert.areSame(node, view.create(node), "should return the same node if it's already a node");
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'));
2051
node = view.create(Y.config.doc.createElement('div'));
2052
Assert.isInstanceOf(Y.Node, node);
2053
Assert.areSame('div', node.get('tagName').toLowerCase());
2056
'remove() should remove the container node from the DOM': function () {
2057
var view = new Y.View();
2059
Y.one('body').append(view.container);
2060
Assert.isTrue(view.container.inDoc());
2063
Assert.isFalse(view.container.inDoc());
2066
'render() should be a chainable noop': function () {
2067
var view = new Y.View();
2068
Assert.areSame(view, view.render());
2072
suite.add(controllerSuite);
2073
suite.add(modelSuite);
2074
suite.add(modelListSuite);
2075
suite.add(viewSuite);
2077
Y.Test.Runner.add(suite);
2080
requires: ['controller', 'model', 'model-list', 'view', 'test']