1(function(QUnit) { 2 3 var view; 4 5 QUnit.module('Backbone.View', { 6 7 beforeEach: function() { 8 $('#qunit-fixture').append( 9 '<div id="testElement"><h1>Test</h1></div>' 10 ); 11 12 view = new Backbone.View({ 13 id: 'test-view', 14 className: 'test-view', 15 other: 'non-special-option' 16 }); 17 }, 18 19 afterEach: function() { 20 $('#testElement').remove(); 21 $('#test-view').remove(); 22 } 23 24 }); 25 26 QUnit.test('constructor', function(assert) { 27 assert.expect(3); 28 assert.equal(view.el.id, 'test-view'); 29 assert.equal(view.el.className, 'test-view'); 30 assert.equal(view.el.other, void 0); 31 }); 32 33 QUnit.test('$', function(assert) { 34 assert.expect(2); 35 var myView = new Backbone.View; 36 myView.setElement('<p><a><b>test</b></a></p>'); 37 var result = myView.$('a b'); 38 39 assert.strictEqual(result[0].innerHTML, 'test'); 40 assert.ok(result.length === +result.length); 41 }); 42 43 QUnit.test('$el', function(assert) { 44 assert.expect(3); 45 var myView = new Backbone.View; 46 myView.setElement('<p><a><b>test</b></a></p>'); 47 assert.strictEqual(myView.el.nodeType, 1); 48 49 assert.ok(myView.$el instanceof Backbone.$); 50 assert.strictEqual(myView.$el[0], myView.el); 51 }); 52 53 QUnit.test('initialize', function(assert) { 54 assert.expect(1); 55 var View = Backbone.View.extend({ 56 initialize: function() { 57 this.one = 1; 58 } 59 }); 60 61 assert.strictEqual(new View().one, 1); 62 }); 63 64 QUnit.test('preinitialize', function(assert) { 65 assert.expect(1); 66 var View = Backbone.View.extend({ 67 preinitialize: function() { 68 this.one = 1; 69 } 70 }); 71 72 assert.strictEqual(new View().one, 1); 73 }); 74 75 QUnit.test('preinitialize occurs before the view is set up', function(assert) { 76 assert.expect(2); 77 var View = Backbone.View.extend({ 78 preinitialize: function() { 79 assert.equal(this.el, undefined); 80 } 81 }); 82 var _view = new View({}); 83 assert.notEqual(_view.el, undefined); 84 }); 85 86 QUnit.test('render', function(assert) { 87 assert.expect(1); 88 var myView = new Backbone.View; 89 assert.equal(myView.render(), myView, '#render returns the view instance'); 90 }); 91 92 QUnit.test('delegateEvents', function(assert) { 93 assert.expect(6); 94 var counter1 = 0, counter2 = 0; 95 96 var myView = new Backbone.View({el: '#testElement'}); 97 myView.increment = function() { counter1++; }; 98 myView.$el.on('click', function() { counter2++; }); 99 100 var events = {'click h1': 'increment'}; 101 102 myView.delegateEvents(events); 103 myView.$('h1').trigger('click'); 104 assert.equal(counter1, 1); 105 assert.equal(counter2, 1); 106 107 myView.$('h1').trigger('click'); 108 assert.equal(counter1, 2); 109 assert.equal(counter2, 2); 110 111 myView.delegateEvents(events); 112 myView.$('h1').trigger('click'); 113 assert.equal(counter1, 3); 114 assert.equal(counter2, 3); 115 }); 116 117 QUnit.test('delegate', function(assert) { 118 assert.expect(3); 119 var myView = new Backbone.View({el: '#testElement'}); 120 myView.delegate('click', 'h1', function() { 121 assert.ok(true); 122 }); 123 myView.delegate('click', function() { 124 assert.ok(true); 125 }); 126 myView.$('h1').trigger('click'); 127 128 assert.equal(myView.delegate(), myView, '#delegate returns the view instance'); 129 }); 130 131 QUnit.test('delegateEvents allows functions for callbacks', function(assert) { 132 assert.expect(3); 133 var myView = new Backbone.View({el: '<p></p>'}); 134 myView.counter = 0; 135 136 var events = { 137 click: function() { 138 this.counter++; 139 } 140 }; 141 142 myView.delegateEvents(events); 143 myView.$el.trigger('click'); 144 assert.equal(myView.counter, 1); 145 146 myView.$el.trigger('click'); 147 assert.equal(myView.counter, 2); 148 149 myView.delegateEvents(events); 150 myView.$el.trigger('click'); 151 assert.equal(myView.counter, 3); 152 }); 153 154 QUnit.test('delegateEvents ignore undefined methods', function(assert) { 155 assert.expect(0); 156 var myView = new Backbone.View({el: '<p></p>'}); 157 myView.delegateEvents({click: 'undefinedMethod'}); 158 myView.$el.trigger('click'); 159 }); 160 161 QUnit.test('undelegateEvents', function(assert) { 162 assert.expect(7); 163 var counter1 = 0, counter2 = 0; 164 165 var myView = new Backbone.View({el: '#testElement'}); 166 myView.increment = function() { counter1++; }; 167 myView.$el.on('click', function() { counter2++; }); 168 169 var events = {'click h1': 'increment'}; 170 171 myView.delegateEvents(events); 172 myView.$('h1').trigger('click'); 173 assert.equal(counter1, 1); 174 assert.equal(counter2, 1); 175 176 myView.undelegateEvents(); 177 myView.$('h1').trigger('click'); 178 assert.equal(counter1, 1); 179 assert.equal(counter2, 2); 180 181 myView.delegateEvents(events); 182 myView.$('h1').trigger('click'); 183 assert.equal(counter1, 2); 184 assert.equal(counter2, 3); 185 186 assert.equal(myView.undelegateEvents(), myView, '#undelegateEvents returns the view instance'); 187 }); 188 189 QUnit.test('undelegate', function(assert) { 190 assert.expect(1); 191 var myView = new Backbone.View({el: '#testElement'}); 192 myView.delegate('click', function() { assert.ok(false); }); 193 myView.delegate('click', 'h1', function() { assert.ok(false); }); 194 195 myView.undelegate('click'); 196 197 myView.$('h1').trigger('click'); 198 myView.$el.trigger('click'); 199 200 assert.equal(myView.undelegate(), myView, '#undelegate returns the view instance'); 201 }); 202 203 QUnit.test('undelegate with passed handler', function(assert) { 204 assert.expect(1); 205 var myView = new Backbone.View({el: '#testElement'}); 206 var listener = function() { assert.ok(false); }; 207 myView.delegate('click', listener); 208 myView.delegate('click', function() { assert.ok(true); }); 209 myView.undelegate('click', listener); 210 myView.$el.trigger('click'); 211 }); 212 213 QUnit.test('undelegate with selector', function(assert) { 214 assert.expect(2); 215 var myView = new Backbone.View({el: '#testElement'}); 216 myView.delegate('click', function() { assert.ok(true); }); 217 myView.delegate('click', 'h1', function() { assert.ok(false); }); 218 myView.undelegate('click', 'h1'); 219 myView.$('h1').trigger('click'); 220 myView.$el.trigger('click'); 221 }); 222 223 QUnit.test('undelegate with handler and selector', function(assert) { 224 assert.expect(2); 225 var myView = new Backbone.View({el: '#testElement'}); 226 myView.delegate('click', function() { assert.ok(true); }); 227 var handler = function() { assert.ok(false); }; 228 myView.delegate('click', 'h1', handler); 229 myView.undelegate('click', 'h1', handler); 230 myView.$('h1').trigger('click'); 231 myView.$el.trigger('click'); 232 }); 233 234 QUnit.test('tagName can be provided as a string', function(assert) { 235 assert.expect(1); 236 var View = Backbone.View.extend({ 237 tagName: 'span' 238 }); 239 240 assert.equal(new View().el.tagName, 'SPAN'); 241 }); 242 243 QUnit.test('tagName can be provided as a function', function(assert) { 244 assert.expect(1); 245 var View = Backbone.View.extend({ 246 tagName: function() { 247 return 'p'; 248 } 249 }); 250 251 assert.ok(new View().$el.is('p')); 252 }); 253 254 QUnit.test('_ensureElement with DOM node el', function(assert) { 255 assert.expect(1); 256 var View = Backbone.View.extend({ 257 el: document.body 258 }); 259 260 assert.equal(new View().el, document.body); 261 }); 262 263 QUnit.test('_ensureElement with string el', function(assert) { 264 assert.expect(3); 265 var View = Backbone.View.extend({ 266 el: 'body' 267 }); 268 assert.strictEqual(new View().el, document.body); 269 270 View = Backbone.View.extend({ 271 el: '#testElement > h1' 272 }); 273 assert.strictEqual(new View().el, $('#testElement > h1').get(0)); 274 275 View = Backbone.View.extend({ 276 el: '#nonexistent' 277 }); 278 assert.ok(!new View().el); 279 }); 280 281 QUnit.test('with className and id functions', function(assert) { 282 assert.expect(2); 283 var View = Backbone.View.extend({ 284 className: function() { 285 return 'className'; 286 }, 287 id: function() { 288 return 'id'; 289 } 290 }); 291 292 assert.strictEqual(new View().el.className, 'className'); 293 assert.strictEqual(new View().el.id, 'id'); 294 }); 295 296 QUnit.test('with attributes', function(assert) { 297 assert.expect(2); 298 var View = Backbone.View.extend({ 299 attributes: { 300 'id': 'id', 301 'class': 'class' 302 } 303 }); 304 305 assert.strictEqual(new View().el.className, 'class'); 306 assert.strictEqual(new View().el.id, 'id'); 307 }); 308 309 QUnit.test('with attributes as a function', function(assert) { 310 assert.expect(1); 311 var View = Backbone.View.extend({ 312 attributes: function() { 313 return {'class': 'dynamic'}; 314 } 315 }); 316 317 assert.strictEqual(new View().el.className, 'dynamic'); 318 }); 319 320 QUnit.test('should default to className/id properties', function(assert) { 321 assert.expect(4); 322 var View = Backbone.View.extend({ 323 className: 'backboneClass', 324 id: 'backboneId', 325 attributes: { 326 'class': 'attributeClass', 327 'id': 'attributeId' 328 } 329 }); 330 331 var myView = new View; 332 assert.strictEqual(myView.el.className, 'backboneClass'); 333 assert.strictEqual(myView.el.id, 'backboneId'); 334 assert.strictEqual(myView.$el.attr('class'), 'backboneClass'); 335 assert.strictEqual(myView.$el.attr('id'), 'backboneId'); 336 }); 337 338 QUnit.test('multiple views per element', function(assert) { 339 assert.expect(3); 340 var count = 0; 341 var $el = $('<p></p>'); 342 343 var View = Backbone.View.extend({ 344 el: $el, 345 events: { 346 click: function() { 347 count++; 348 } 349 } 350 }); 351 352 var view1 = new View; 353 $el.trigger('click'); 354 assert.equal(1, count); 355 356 var view2 = new View; 357 $el.trigger('click'); 358 assert.equal(3, count); 359 360 view1.delegateEvents(); 361 $el.trigger('click'); 362 assert.equal(5, count); 363 }); 364 365 QUnit.test('custom events', function(assert) { 366 assert.expect(2); 367 var View = Backbone.View.extend({ 368 el: $('body'), 369 events: { 370 fake$event: function() { assert.ok(true); } 371 } 372 }); 373 374 var myView = new View; 375 $('body').trigger('fake$event').trigger('fake$event'); 376 377 $('body').off('fake$event'); 378 $('body').trigger('fake$event'); 379 }); 380 381 QUnit.test('#1048 - setElement uses provided object.', function(assert) { 382 assert.expect(2); 383 var $el = $('body'); 384 385 var myView = new Backbone.View({el: $el}); 386 assert.ok(myView.$el === $el); 387 388 myView.setElement($el = $($el)); 389 assert.ok(myView.$el === $el); 390 }); 391 392 QUnit.test('#986 - Undelegate before changing element.', function(assert) { 393 assert.expect(1); 394 var button1 = $('<button></button>'); 395 var button2 = $('<button></button>'); 396 397 var View = Backbone.View.extend({ 398 events: { 399 click: function(e) { 400 assert.ok(myView.el === e.target); 401 } 402 } 403 }); 404 405 var myView = new View({el: button1}); 406 myView.setElement(button2); 407 408 button1.trigger('click'); 409 button2.trigger('click'); 410 }); 411 412 QUnit.test('#1172 - Clone attributes object', function(assert) { 413 assert.expect(2); 414 var View = Backbone.View.extend({ 415 attributes: {foo: 'bar'} 416 }); 417 418 var view1 = new View({id: 'foo'}); 419 assert.strictEqual(view1.el.id, 'foo'); 420 421 var view2 = new View(); 422 assert.ok(!view2.el.id); 423 }); 424 425 QUnit.test('views stopListening', function(assert) { 426 assert.expect(0); 427 var View = Backbone.View.extend({ 428 initialize: function() { 429 this.listenTo(this.model, 'all x', function() { assert.ok(false); }); 430 this.listenTo(this.collection, 'all x', function() { assert.ok(false); }); 431 } 432 }); 433 434 var myView = new View({ 435 model: new Backbone.Model, 436 collection: new Backbone.Collection 437 }); 438 439 myView.stopListening(); 440 myView.model.trigger('x'); 441 myView.collection.trigger('x'); 442 }); 443 444 QUnit.test('Provide function for el.', function(assert) { 445 assert.expect(2); 446 var View = Backbone.View.extend({ 447 el: function() { 448 return '<p><a></a></p>'; 449 } 450 }); 451 452 var myView = new View; 453 assert.ok(myView.$el.is('p')); 454 assert.ok(myView.$el.has('a')); 455 }); 456 457 QUnit.test('events passed in options', function(assert) { 458 assert.expect(1); 459 var counter = 0; 460 461 var View = Backbone.View.extend({ 462 el: '#testElement', 463 increment: function() { 464 counter++; 465 } 466 }); 467 468 var myView = new View({ 469 events: { 470 'click h1': 'increment' 471 } 472 }); 473 474 myView.$('h1').trigger('click').trigger('click'); 475 assert.equal(counter, 2); 476 }); 477 478 QUnit.test('remove', function(assert) { 479 assert.expect(2); 480 var myView = new Backbone.View; 481 document.body.appendChild(view.el); 482 483 myView.delegate('click', function() { assert.ok(false); }); 484 myView.listenTo(myView, 'all x', function() { assert.ok(false); }); 485 486 assert.equal(myView.remove(), myView, '#remove returns the view instance'); 487 myView.$el.trigger('click'); 488 myView.trigger('x'); 489 490 // In IE8 and below, parentNode still exists but is not document.body. 491 assert.notEqual(myView.el.parentNode, document.body); 492 }); 493 494 QUnit.test('setElement', function(assert) { 495 assert.expect(3); 496 var myView = new Backbone.View({ 497 events: { 498 click: function() { assert.ok(false); } 499 } 500 }); 501 myView.events = { 502 click: function() { assert.ok(true); } 503 }; 504 var oldEl = myView.el; 505 var $oldEl = myView.$el; 506 507 myView.setElement(document.createElement('div')); 508 509 $oldEl.click(); 510 myView.$el.click(); 511 512 assert.notEqual(oldEl, myView.el); 513 assert.notEqual($oldEl, myView.$el); 514 }); 515 516})(QUnit); 517