--- /dev/null
+(function() {
+
+ var view;
+
+ QUnit.module('Backbone.View', {
+
+ beforeEach: function(assert) {
+ $('#qunit-fixture').append(
+ '<div id="testElement"><h1>Test</h1></div>'
+ );
+
+ view = new Backbone.View({
+ id: 'test-view',
+ className: 'test-view',
+ other: 'non-special-option'
+ });
+ },
+
+ afterEach: function() {
+ $('#testElement').remove();
+ $('#test-view').remove();
+ }
+
+ });
+
+ QUnit.test('constructor', function(assert) {
+ assert.expect(3);
+ assert.equal(view.el.id, 'test-view');
+ assert.equal(view.el.className, 'test-view');
+ assert.equal(view.el.other, void 0);
+ });
+
+ QUnit.test('$', function(assert) {
+ assert.expect(2);
+ var myView = new Backbone.View;
+ myView.setElement('<p><a><b>test</b></a></p>');
+ var result = myView.$('a b');
+
+ assert.strictEqual(result[0].innerHTML, 'test');
+ assert.ok(result.length === +result.length);
+ });
+
+ QUnit.test('$el', function(assert) {
+ assert.expect(3);
+ var myView = new Backbone.View;
+ myView.setElement('<p><a><b>test</b></a></p>');
+ assert.strictEqual(myView.el.nodeType, 1);
+
+ assert.ok(myView.$el instanceof Backbone.$);
+ assert.strictEqual(myView.$el[0], myView.el);
+ });
+
+ QUnit.test('initialize', function(assert) {
+ assert.expect(1);
+ var View = Backbone.View.extend({
+ initialize: function() {
+ this.one = 1;
+ }
+ });
+
+ assert.strictEqual(new View().one, 1);
+ });
+
+ QUnit.test('render', function(assert) {
+ assert.expect(1);
+ var myView = new Backbone.View;
+ assert.equal(myView.render(), myView, '#render returns the view instance');
+ });
+
+ QUnit.test('delegateEvents', function(assert) {
+ assert.expect(6);
+ var counter1 = 0, counter2 = 0;
+
+ var myView = new Backbone.View({el: '#testElement'});
+ myView.increment = function(){ counter1++; };
+ myView.$el.on('click', function(){ counter2++; });
+
+ var events = {'click h1': 'increment'};
+
+ myView.delegateEvents(events);
+ myView.$('h1').trigger('click');
+ assert.equal(counter1, 1);
+ assert.equal(counter2, 1);
+
+ myView.$('h1').trigger('click');
+ assert.equal(counter1, 2);
+ assert.equal(counter2, 2);
+
+ myView.delegateEvents(events);
+ myView.$('h1').trigger('click');
+ assert.equal(counter1, 3);
+ assert.equal(counter2, 3);
+ });
+
+ QUnit.test('delegate', function(assert) {
+ assert.expect(3);
+ var myView = new Backbone.View({el: '#testElement'});
+ myView.delegate('click', 'h1', function() {
+ assert.ok(true);
+ });
+ myView.delegate('click', function() {
+ assert.ok(true);
+ });
+ myView.$('h1').trigger('click');
+
+ assert.equal(myView.delegate(), myView, '#delegate returns the view instance');
+ });
+
+ QUnit.test('delegateEvents allows functions for callbacks', function(assert) {
+ assert.expect(3);
+ var myView = new Backbone.View({el: '<p></p>'});
+ myView.counter = 0;
+
+ var events = {
+ click: function() {
+ this.counter++;
+ }
+ };
+
+ myView.delegateEvents(events);
+ myView.$el.trigger('click');
+ assert.equal(myView.counter, 1);
+
+ myView.$el.trigger('click');
+ assert.equal(myView.counter, 2);
+
+ myView.delegateEvents(events);
+ myView.$el.trigger('click');
+ assert.equal(myView.counter, 3);
+ });
+
+
+ QUnit.test('delegateEvents ignore undefined methods', function(assert) {
+ assert.expect(0);
+ var myView = new Backbone.View({el: '<p></p>'});
+ myView.delegateEvents({'click': 'undefinedMethod'});
+ myView.$el.trigger('click');
+ });
+
+ QUnit.test('undelegateEvents', function(assert) {
+ assert.expect(7);
+ var counter1 = 0, counter2 = 0;
+
+ var myView = new Backbone.View({el: '#testElement'});
+ myView.increment = function(){ counter1++; };
+ myView.$el.on('click', function(){ counter2++; });
+
+ var events = {'click h1': 'increment'};
+
+ myView.delegateEvents(events);
+ myView.$('h1').trigger('click');
+ assert.equal(counter1, 1);
+ assert.equal(counter2, 1);
+
+ myView.undelegateEvents();
+ myView.$('h1').trigger('click');
+ assert.equal(counter1, 1);
+ assert.equal(counter2, 2);
+
+ myView.delegateEvents(events);
+ myView.$('h1').trigger('click');
+ assert.equal(counter1, 2);
+ assert.equal(counter2, 3);
+
+ assert.equal(myView.undelegateEvents(), myView, '#undelegateEvents returns the view instance');
+ });
+
+ QUnit.test('undelegate', function(assert) {
+ assert.expect(1);
+ var myView = new Backbone.View({el: '#testElement'});
+ myView.delegate('click', function() { assert.ok(false); });
+ myView.delegate('click', 'h1', function() { assert.ok(false); });
+
+ myView.undelegate('click');
+
+ myView.$('h1').trigger('click');
+ myView.$el.trigger('click');
+
+ assert.equal(myView.undelegate(), myView, '#undelegate returns the view instance');
+ });
+
+ QUnit.test('undelegate with passed handler', function(assert) {
+ assert.expect(1);
+ var myView = new Backbone.View({el: '#testElement'});
+ var listener = function() { assert.ok(false); };
+ myView.delegate('click', listener);
+ myView.delegate('click', function() { assert.ok(true); });
+ myView.undelegate('click', listener);
+ myView.$el.trigger('click');
+ });
+
+ QUnit.test('undelegate with selector', function(assert) {
+ assert.expect(2);
+ var myView = new Backbone.View({el: '#testElement'});
+ myView.delegate('click', function() { assert.ok(true); });
+ myView.delegate('click', 'h1', function() { assert.ok(false); });
+ myView.undelegate('click', 'h1');
+ myView.$('h1').trigger('click');
+ myView.$el.trigger('click');
+ });
+
+ QUnit.test('undelegate with handler and selector', function(assert) {
+ assert.expect(2);
+ var myView = new Backbone.View({el: '#testElement'});
+ myView.delegate('click', function() { assert.ok(true); });
+ var handler = function(){ assert.ok(false); };
+ myView.delegate('click', 'h1', handler);
+ myView.undelegate('click', 'h1', handler);
+ myView.$('h1').trigger('click');
+ myView.$el.trigger('click');
+ });
+
+ QUnit.test('tagName can be provided as a string', function(assert) {
+ assert.expect(1);
+ var View = Backbone.View.extend({
+ tagName: 'span'
+ });
+
+ assert.equal(new View().el.tagName, 'SPAN');
+ });
+
+ QUnit.test('tagName can be provided as a function', function(assert) {
+ assert.expect(1);
+ var View = Backbone.View.extend({
+ tagName: function() {
+ return 'p';
+ }
+ });
+
+ assert.ok(new View().$el.is('p'));
+ });
+
+ QUnit.test('_ensureElement with DOM node el', function(assert) {
+ assert.expect(1);
+ var View = Backbone.View.extend({
+ el: document.body
+ });
+
+ assert.equal(new View().el, document.body);
+ });
+
+ QUnit.test('_ensureElement with string el', function(assert) {
+ assert.expect(3);
+ var View = Backbone.View.extend({
+ el: 'body'
+ });
+ assert.strictEqual(new View().el, document.body);
+
+ View = Backbone.View.extend({
+ el: '#testElement > h1'
+ });
+ assert.strictEqual(new View().el, $('#testElement > h1').get(0));
+
+ View = Backbone.View.extend({
+ el: '#nonexistent'
+ });
+ assert.ok(!new View().el);
+ });
+
+ QUnit.test('with className and id functions', function(assert) {
+ assert.expect(2);
+ var View = Backbone.View.extend({
+ className: function() {
+ return 'className';
+ },
+ id: function() {
+ return 'id';
+ }
+ });
+
+ assert.strictEqual(new View().el.className, 'className');
+ assert.strictEqual(new View().el.id, 'id');
+ });
+
+ QUnit.test('with attributes', function(assert) {
+ assert.expect(2);
+ var View = Backbone.View.extend({
+ attributes: {
+ 'id': 'id',
+ 'class': 'class'
+ }
+ });
+
+ assert.strictEqual(new View().el.className, 'class');
+ assert.strictEqual(new View().el.id, 'id');
+ });
+
+ QUnit.test('with attributes as a function', function(assert) {
+ assert.expect(1);
+ var View = Backbone.View.extend({
+ attributes: function() {
+ return {'class': 'dynamic'};
+ }
+ });
+
+ assert.strictEqual(new View().el.className, 'dynamic');
+ });
+
+ QUnit.test('should default to className/id properties', function(assert) {
+ assert.expect(4);
+ var View = Backbone.View.extend({
+ className: 'backboneClass',
+ id: 'backboneId',
+ attributes: {
+ 'class': 'attributeClass',
+ 'id': 'attributeId'
+ }
+ });
+
+ var myView = new View;
+ assert.strictEqual(myView.el.className, 'backboneClass');
+ assert.strictEqual(myView.el.id, 'backboneId');
+ assert.strictEqual(myView.$el.attr('class'), 'backboneClass');
+ assert.strictEqual(myView.$el.attr('id'), 'backboneId');
+ });
+
+ QUnit.test('multiple views per element', function(assert) {
+ assert.expect(3);
+ var count = 0;
+ var $el = $('<p></p>');
+
+ var View = Backbone.View.extend({
+ el: $el,
+ events: {
+ click: function() {
+ count++;
+ }
+ }
+ });
+
+ var view1 = new View;
+ $el.trigger('click');
+ assert.equal(1, count);
+
+ var view2 = new View;
+ $el.trigger('click');
+ assert.equal(3, count);
+
+ view1.delegateEvents();
+ $el.trigger('click');
+ assert.equal(5, count);
+ });
+
+ QUnit.test('custom events', function(assert) {
+ assert.expect(2);
+ var View = Backbone.View.extend({
+ el: $('body'),
+ events: {
+ fake$event: function() { assert.ok(true); }
+ }
+ });
+
+ var myView = new View;
+ $('body').trigger('fake$event').trigger('fake$event');
+
+ $('body').off('fake$event');
+ $('body').trigger('fake$event');
+ });
+
+ QUnit.test('#1048 - setElement uses provided object.', function(assert) {
+ assert.expect(2);
+ var $el = $('body');
+
+ var myView = new Backbone.View({el: $el});
+ assert.ok(myView.$el === $el);
+
+ myView.setElement($el = $($el));
+ assert.ok(myView.$el === $el);
+ });
+
+ QUnit.test('#986 - Undelegate before changing element.', function(assert) {
+ assert.expect(1);
+ var button1 = $('<button></button>');
+ var button2 = $('<button></button>');
+
+ var View = Backbone.View.extend({
+ events: {
+ click: function(e) {
+ assert.ok(myView.el === e.target);
+ }
+ }
+ });
+
+ var myView = new View({el: button1});
+ myView.setElement(button2);
+
+ button1.trigger('click');
+ button2.trigger('click');
+ });
+
+ QUnit.test('#1172 - Clone attributes object', function(assert) {
+ assert.expect(2);
+ var View = Backbone.View.extend({
+ attributes: {foo: 'bar'}
+ });
+
+ var view1 = new View({id: 'foo'});
+ assert.strictEqual(view1.el.id, 'foo');
+
+ var view2 = new View();
+ assert.ok(!view2.el.id);
+ });
+
+ QUnit.test('views stopListening', function(assert) {
+ assert.expect(0);
+ var View = Backbone.View.extend({
+ initialize: function() {
+ this.listenTo(this.model, 'all x', function(){ assert.ok(false); });
+ this.listenTo(this.collection, 'all x', function(){ assert.ok(false); });
+ }
+ });
+
+ var myView = new View({
+ model: new Backbone.Model,
+ collection: new Backbone.Collection
+ });
+
+ myView.stopListening();
+ myView.model.trigger('x');
+ myView.collection.trigger('x');
+ });
+
+ QUnit.test('Provide function for el.', function(assert) {
+ assert.expect(2);
+ var View = Backbone.View.extend({
+ el: function() {
+ return '<p><a></a></p>';
+ }
+ });
+
+ var myView = new View;
+ assert.ok(myView.$el.is('p'));
+ assert.ok(myView.$el.has('a'));
+ });
+
+ QUnit.test('events passed in options', function(assert) {
+ assert.expect(1);
+ var counter = 0;
+
+ var View = Backbone.View.extend({
+ el: '#testElement',
+ increment: function() {
+ counter++;
+ }
+ });
+
+ var myView = new View({
+ events: {
+ 'click h1': 'increment'
+ }
+ });
+
+ myView.$('h1').trigger('click').trigger('click');
+ assert.equal(counter, 2);
+ });
+
+ QUnit.test('remove', function(assert) {
+ assert.expect(2);
+ var myView = new Backbone.View;
+ document.body.appendChild(view.el);
+
+ myView.delegate('click', function() { assert.ok(false); });
+ myView.listenTo(myView, 'all x', function() { assert.ok(false); });
+
+ assert.equal(myView.remove(), myView, '#remove returns the view instance');
+ myView.$el.trigger('click');
+ myView.trigger('x');
+
+ // In IE8 and below, parentNode still exists but is not document.body.
+ assert.notEqual(myView.el.parentNode, document.body);
+ });
+
+ QUnit.test('setElement', function(assert) {
+ assert.expect(3);
+ var myView = new Backbone.View({
+ events: {
+ click: function() { assert.ok(false); }
+ }
+ });
+ myView.events = {
+ click: function() { assert.ok(true); }
+ };
+ var oldEl = myView.el;
+ var $oldEl = myView.$el;
+
+ myView.setElement(document.createElement('div'));
+
+ $oldEl.click();
+ myView.$el.click();
+
+ assert.notEqual(oldEl, myView.el);
+ assert.notEqual($oldEl, myView.$el);
+ });
+
+})();