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