Lots of updates

This commit is contained in:
baldo 2016-05-16 13:33:49 +02:00
parent e3cfff8310
commit 39e7af6238
454 changed files with 221168 additions and 36622 deletions

View file

@ -0,0 +1,22 @@
Copyright (c) 2010-2016 Jeremy Ashkenas, DocumentCloud
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,706 @@
(function() {
QUnit.module('Backbone.Events');
QUnit.test('on and trigger', function(assert) {
assert.expect(2);
var obj = {counter: 0};
_.extend(obj, Backbone.Events);
obj.on('event', function() { obj.counter += 1; });
obj.trigger('event');
assert.equal(obj.counter, 1, 'counter should be incremented.');
obj.trigger('event');
obj.trigger('event');
obj.trigger('event');
obj.trigger('event');
assert.equal(obj.counter, 5, 'counter should be incremented five times.');
});
QUnit.test('binding and triggering multiple events', function(assert) {
assert.expect(4);
var obj = {counter: 0};
_.extend(obj, Backbone.Events);
obj.on('a b c', function() { obj.counter += 1; });
obj.trigger('a');
assert.equal(obj.counter, 1);
obj.trigger('a b');
assert.equal(obj.counter, 3);
obj.trigger('c');
assert.equal(obj.counter, 4);
obj.off('a c');
obj.trigger('a b c');
assert.equal(obj.counter, 5);
});
QUnit.test('binding and triggering with event maps', function(assert) {
var obj = {counter: 0};
_.extend(obj, Backbone.Events);
var increment = function() {
this.counter += 1;
};
obj.on({
a: increment,
b: increment,
c: increment
}, obj);
obj.trigger('a');
assert.equal(obj.counter, 1);
obj.trigger('a b');
assert.equal(obj.counter, 3);
obj.trigger('c');
assert.equal(obj.counter, 4);
obj.off({
a: increment,
c: increment
}, obj);
obj.trigger('a b c');
assert.equal(obj.counter, 5);
});
QUnit.test('binding and triggering multiple event names with event maps', function(assert) {
var obj = {counter: 0};
_.extend(obj, Backbone.Events);
var increment = function() {
this.counter += 1;
};
obj.on({
'a b c': increment
});
obj.trigger('a');
assert.equal(obj.counter, 1);
obj.trigger('a b');
assert.equal(obj.counter, 3);
obj.trigger('c');
assert.equal(obj.counter, 4);
obj.off({
'a c': increment
});
obj.trigger('a b c');
assert.equal(obj.counter, 5);
});
QUnit.test('binding and trigger with event maps context', function(assert) {
assert.expect(2);
var obj = {counter: 0};
var context = {};
_.extend(obj, Backbone.Events);
obj.on({
a: function() {
assert.strictEqual(this, context, 'defaults `context` to `callback` param');
}
}, context).trigger('a');
obj.off().on({
a: function() {
assert.strictEqual(this, context, 'will not override explicit `context` param');
}
}, this, context).trigger('a');
});
QUnit.test('listenTo and stopListening', function(assert) {
assert.expect(1);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
a.listenTo(b, 'all', function(){ assert.ok(true); });
b.trigger('anything');
a.listenTo(b, 'all', function(){ assert.ok(false); });
a.stopListening();
b.trigger('anything');
});
QUnit.test('listenTo and stopListening with event maps', function(assert) {
assert.expect(4);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
var cb = function(){ assert.ok(true); };
a.listenTo(b, {event: cb});
b.trigger('event');
a.listenTo(b, {event2: cb});
b.on('event2', cb);
a.stopListening(b, {event2: cb});
b.trigger('event event2');
a.stopListening();
b.trigger('event event2');
});
QUnit.test('stopListening with omitted args', function(assert) {
assert.expect(2);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
var cb = function() { assert.ok(true); };
a.listenTo(b, 'event', cb);
b.on('event', cb);
a.listenTo(b, 'event2', cb);
a.stopListening(null, {event: cb});
b.trigger('event event2');
b.off();
a.listenTo(b, 'event event2', cb);
a.stopListening(null, 'event');
a.stopListening();
b.trigger('event2');
});
QUnit.test('listenToOnce', function(assert) {
assert.expect(2);
// Same as the previous test, but we use once rather than having to explicitly unbind
var obj = {counterA: 0, counterB: 0};
_.extend(obj, Backbone.Events);
var incrA = function(){ obj.counterA += 1; obj.trigger('event'); };
var incrB = function(){ obj.counterB += 1; };
obj.listenToOnce(obj, 'event', incrA);
obj.listenToOnce(obj, 'event', incrB);
obj.trigger('event');
assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.');
});
QUnit.test('listenToOnce and stopListening', function(assert) {
assert.expect(1);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
a.listenToOnce(b, 'all', function() { assert.ok(true); });
b.trigger('anything');
b.trigger('anything');
a.listenToOnce(b, 'all', function() { assert.ok(false); });
a.stopListening();
b.trigger('anything');
});
QUnit.test('listenTo, listenToOnce and stopListening', function(assert) {
assert.expect(1);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
a.listenToOnce(b, 'all', function() { assert.ok(true); });
b.trigger('anything');
b.trigger('anything');
a.listenTo(b, 'all', function() { assert.ok(false); });
a.stopListening();
b.trigger('anything');
});
QUnit.test('listenTo and stopListening with event maps', function(assert) {
assert.expect(1);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
a.listenTo(b, {change: function(){ assert.ok(true); }});
b.trigger('change');
a.listenTo(b, {change: function(){ assert.ok(false); }});
a.stopListening();
b.trigger('change');
});
QUnit.test('listenTo yourself', function(assert) {
assert.expect(1);
var e = _.extend({}, Backbone.Events);
e.listenTo(e, 'foo', function(){ assert.ok(true); });
e.trigger('foo');
});
QUnit.test('listenTo yourself cleans yourself up with stopListening', function(assert) {
assert.expect(1);
var e = _.extend({}, Backbone.Events);
e.listenTo(e, 'foo', function(){ assert.ok(true); });
e.trigger('foo');
e.stopListening();
e.trigger('foo');
});
QUnit.test('stopListening cleans up references', function(assert) {
assert.expect(12);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
var fn = function() {};
b.on('event', fn);
a.listenTo(b, 'event', fn).stopListening();
assert.equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0);
a.listenTo(b, 'event', fn).stopListening(b);
assert.equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0);
a.listenTo(b, 'event', fn).stopListening(b, 'event');
assert.equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0);
a.listenTo(b, 'event', fn).stopListening(b, 'event', fn);
assert.equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0);
});
QUnit.test('stopListening cleans up references from listenToOnce', function(assert) {
assert.expect(12);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
var fn = function() {};
b.on('event', fn);
a.listenToOnce(b, 'event', fn).stopListening();
assert.equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0);
a.listenToOnce(b, 'event', fn).stopListening(b);
assert.equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0);
a.listenToOnce(b, 'event', fn).stopListening(b, 'event');
assert.equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0);
a.listenToOnce(b, 'event', fn).stopListening(b, 'event', fn);
assert.equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._events.event), 1);
assert.equal(_.size(b._listeners), 0);
});
QUnit.test('listenTo and off cleaning up references', function(assert) {
assert.expect(8);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
var fn = function() {};
a.listenTo(b, 'event', fn);
b.off();
assert.equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._listeners), 0);
a.listenTo(b, 'event', fn);
b.off('event');
assert.equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._listeners), 0);
a.listenTo(b, 'event', fn);
b.off(null, fn);
assert.equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._listeners), 0);
a.listenTo(b, 'event', fn);
b.off(null, null, a);
assert.equal(_.size(a._listeningTo), 0);
assert.equal(_.size(b._listeners), 0);
});
QUnit.test('listenTo and stopListening cleaning up references', function(assert) {
assert.expect(2);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
a.listenTo(b, 'all', function(){ assert.ok(true); });
b.trigger('anything');
a.listenTo(b, 'other', function(){ assert.ok(false); });
a.stopListening(b, 'other');
a.stopListening(b, 'all');
assert.equal(_.size(a._listeningTo), 0);
});
QUnit.test('listenToOnce without context cleans up references after the event has fired', function(assert) {
assert.expect(2);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
a.listenToOnce(b, 'all', function(){ assert.ok(true); });
b.trigger('anything');
assert.equal(_.size(a._listeningTo), 0);
});
QUnit.test('listenToOnce with event maps cleans up references', function(assert) {
assert.expect(2);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
a.listenToOnce(b, {
one: function() { assert.ok(true); },
two: function() { assert.ok(false); }
});
b.trigger('one');
assert.equal(_.size(a._listeningTo), 1);
});
QUnit.test('listenToOnce with event maps binds the correct `this`', function(assert) {
assert.expect(1);
var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
a.listenToOnce(b, {
one: function() { assert.ok(this === a); },
two: function() { assert.ok(false); }
});
b.trigger('one');
});
QUnit.test("listenTo with empty callback doesn't throw an error", function(assert) {
assert.expect(1);
var e = _.extend({}, Backbone.Events);
e.listenTo(e, 'foo', null);
e.trigger('foo');
assert.ok(true);
});
QUnit.test('trigger all for each event', function(assert) {
assert.expect(3);
var a, b, obj = {counter: 0};
_.extend(obj, Backbone.Events);
obj.on('all', function(event) {
obj.counter++;
if (event === 'a') a = true;
if (event === 'b') b = true;
})
.trigger('a b');
assert.ok(a);
assert.ok(b);
assert.equal(obj.counter, 2);
});
QUnit.test('on, then unbind all functions', function(assert) {
assert.expect(1);
var obj = {counter: 0};
_.extend(obj, Backbone.Events);
var callback = function() { obj.counter += 1; };
obj.on('event', callback);
obj.trigger('event');
obj.off('event');
obj.trigger('event');
assert.equal(obj.counter, 1, 'counter should have only been incremented once.');
});
QUnit.test('bind two callbacks, unbind only one', function(assert) {
assert.expect(2);
var obj = {counterA: 0, counterB: 0};
_.extend(obj, Backbone.Events);
var callback = function() { obj.counterA += 1; };
obj.on('event', callback);
obj.on('event', function() { obj.counterB += 1; });
obj.trigger('event');
obj.off('event', callback);
obj.trigger('event');
assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
assert.equal(obj.counterB, 2, 'counterB should have been incremented twice.');
});
QUnit.test('unbind a callback in the midst of it firing', function(assert) {
assert.expect(1);
var obj = {counter: 0};
_.extend(obj, Backbone.Events);
var callback = function() {
obj.counter += 1;
obj.off('event', callback);
};
obj.on('event', callback);
obj.trigger('event');
obj.trigger('event');
obj.trigger('event');
assert.equal(obj.counter, 1, 'the callback should have been unbound.');
});
QUnit.test('two binds that unbind themeselves', function(assert) {
assert.expect(2);
var obj = {counterA: 0, counterB: 0};
_.extend(obj, Backbone.Events);
var incrA = function(){ obj.counterA += 1; obj.off('event', incrA); };
var incrB = function(){ obj.counterB += 1; obj.off('event', incrB); };
obj.on('event', incrA);
obj.on('event', incrB);
obj.trigger('event');
obj.trigger('event');
obj.trigger('event');
assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.');
});
QUnit.test('bind a callback with a default context when none supplied', function(assert) {
assert.expect(1);
var obj = _.extend({
assertTrue: function() {
assert.equal(this, obj, '`this` was bound to the callback');
}
}, Backbone.Events);
obj.once('event', obj.assertTrue);
obj.trigger('event');
});
QUnit.test('bind a callback with a supplied context', function(assert) {
assert.expect(1);
var TestClass = function() {
return this;
};
TestClass.prototype.assertTrue = function() {
assert.ok(true, '`this` was bound to the callback');
};
var obj = _.extend({}, Backbone.Events);
obj.on('event', function() { this.assertTrue(); }, new TestClass);
obj.trigger('event');
});
QUnit.test('nested trigger with unbind', function(assert) {
assert.expect(1);
var obj = {counter: 0};
_.extend(obj, Backbone.Events);
var incr1 = function(){ obj.counter += 1; obj.off('event', incr1); obj.trigger('event'); };
var incr2 = function(){ obj.counter += 1; };
obj.on('event', incr1);
obj.on('event', incr2);
obj.trigger('event');
assert.equal(obj.counter, 3, 'counter should have been incremented three times');
});
QUnit.test('callback list is not altered during trigger', function(assert) {
assert.expect(2);
var counter = 0, obj = _.extend({}, Backbone.Events);
var incr = function(){ counter++; };
var incrOn = function(){ obj.on('event all', incr); };
var incrOff = function(){ obj.off('event all', incr); };
obj.on('event all', incrOn).trigger('event');
assert.equal(counter, 0, 'on does not alter callback list');
obj.off().on('event', incrOff).on('event all', incr).trigger('event');
assert.equal(counter, 2, 'off does not alter callback list');
});
QUnit.test("#1282 - 'all' callback list is retrieved after each event.", function(assert) {
assert.expect(1);
var counter = 0;
var obj = _.extend({}, Backbone.Events);
var incr = function(){ counter++; };
obj.on('x', function() {
obj.on('y', incr).on('all', incr);
})
.trigger('x y');
assert.strictEqual(counter, 2);
});
QUnit.test('if no callback is provided, `on` is a noop', function(assert) {
assert.expect(0);
_.extend({}, Backbone.Events).on('test').trigger('test');
});
QUnit.test('if callback is truthy but not a function, `on` should throw an error just like jQuery', function(assert) {
assert.expect(1);
var view = _.extend({}, Backbone.Events).on('test', 'noop');
assert.raises(function() {
view.trigger('test');
});
});
QUnit.test('remove all events for a specific context', function(assert) {
assert.expect(4);
var obj = _.extend({}, Backbone.Events);
obj.on('x y all', function() { assert.ok(true); });
obj.on('x y all', function() { assert.ok(false); }, obj);
obj.off(null, null, obj);
obj.trigger('x y');
});
QUnit.test('remove all events for a specific callback', function(assert) {
assert.expect(4);
var obj = _.extend({}, Backbone.Events);
var success = function() { assert.ok(true); };
var fail = function() { assert.ok(false); };
obj.on('x y all', success);
obj.on('x y all', fail);
obj.off(null, fail);
obj.trigger('x y');
});
QUnit.test('#1310 - off does not skip consecutive events', function(assert) {
assert.expect(0);
var obj = _.extend({}, Backbone.Events);
obj.on('event', function() { assert.ok(false); }, obj);
obj.on('event', function() { assert.ok(false); }, obj);
obj.off(null, null, obj);
obj.trigger('event');
});
QUnit.test('once', function(assert) {
assert.expect(2);
// Same as the previous test, but we use once rather than having to explicitly unbind
var obj = {counterA: 0, counterB: 0};
_.extend(obj, Backbone.Events);
var incrA = function(){ obj.counterA += 1; obj.trigger('event'); };
var incrB = function(){ obj.counterB += 1; };
obj.once('event', incrA);
obj.once('event', incrB);
obj.trigger('event');
assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.');
});
QUnit.test('once variant one', function(assert) {
assert.expect(3);
var f = function(){ assert.ok(true); };
var a = _.extend({}, Backbone.Events).once('event', f);
var b = _.extend({}, Backbone.Events).on('event', f);
a.trigger('event');
b.trigger('event');
b.trigger('event');
});
QUnit.test('once variant two', function(assert) {
assert.expect(3);
var f = function(){ assert.ok(true); };
var obj = _.extend({}, Backbone.Events);
obj
.once('event', f)
.on('event', f)
.trigger('event')
.trigger('event');
});
QUnit.test('once with off', function(assert) {
assert.expect(0);
var f = function(){ assert.ok(true); };
var obj = _.extend({}, Backbone.Events);
obj.once('event', f);
obj.off('event', f);
obj.trigger('event');
});
QUnit.test('once with event maps', function(assert) {
var obj = {counter: 0};
_.extend(obj, Backbone.Events);
var increment = function() {
this.counter += 1;
};
obj.once({
a: increment,
b: increment,
c: increment
}, obj);
obj.trigger('a');
assert.equal(obj.counter, 1);
obj.trigger('a b');
assert.equal(obj.counter, 2);
obj.trigger('c');
assert.equal(obj.counter, 3);
obj.trigger('a b c');
assert.equal(obj.counter, 3);
});
QUnit.test('bind a callback with a supplied context using once with object notation', function(assert) {
assert.expect(1);
var obj = {counter: 0};
var context = {};
_.extend(obj, Backbone.Events);
obj.once({
a: function() {
assert.strictEqual(this, context, 'defaults `context` to `callback` param');
}
}, context).trigger('a');
});
QUnit.test('once with off only by context', function(assert) {
assert.expect(0);
var context = {};
var obj = _.extend({}, Backbone.Events);
obj.once('event', function(){ assert.ok(false); }, context);
obj.off(null, null, context);
obj.trigger('event');
});
QUnit.test('Backbone object inherits Events', function(assert) {
assert.ok(Backbone.on === Backbone.Events.on);
});
QUnit.test('once with asynchronous events', function(assert) {
var done = assert.async();
assert.expect(1);
var func = _.debounce(function() { assert.ok(true); done(); }, 50);
var obj = _.extend({}, Backbone.Events).once('async', func);
obj.trigger('async');
obj.trigger('async');
});
QUnit.test('once with multiple events.', function(assert) {
assert.expect(2);
var obj = _.extend({}, Backbone.Events);
obj.once('x y', function() { assert.ok(true); });
obj.trigger('x y');
});
QUnit.test('Off during iteration with once.', function(assert) {
assert.expect(2);
var obj = _.extend({}, Backbone.Events);
var f = function(){ this.off('event', f); };
obj.on('event', f);
obj.once('event', function(){});
obj.on('event', function(){ assert.ok(true); });
obj.trigger('event');
obj.trigger('event');
});
QUnit.test('`once` on `all` should work as expected', function(assert) {
assert.expect(1);
Backbone.once('all', function() {
assert.ok(true);
Backbone.trigger('all');
});
Backbone.trigger('all');
});
QUnit.test('once without a callback is a noop', function(assert) {
assert.expect(0);
_.extend({}, Backbone.Events).once('event').trigger('event');
});
QUnit.test('listenToOnce without a callback is a noop', function(assert) {
assert.expect(0);
var obj = _.extend({}, Backbone.Events);
obj.listenToOnce(obj, 'event').trigger('event');
});
QUnit.test('event functions are chainable', function(assert) {
var obj = _.extend({}, Backbone.Events);
var obj2 = _.extend({}, Backbone.Events);
var fn = function() {};
assert.equal(obj, obj.trigger('noeventssetyet'));
assert.equal(obj, obj.off('noeventssetyet'));
assert.equal(obj, obj.stopListening('noeventssetyet'));
assert.equal(obj, obj.on('a', fn));
assert.equal(obj, obj.once('c', fn));
assert.equal(obj, obj.trigger('a'));
assert.equal(obj, obj.listenTo(obj2, 'a', fn));
assert.equal(obj, obj.listenToOnce(obj2, 'b', fn));
assert.equal(obj, obj.off('a c'));
assert.equal(obj, obj.stopListening(obj2, 'a'));
assert.equal(obj, obj.stopListening());
});
QUnit.test('#3448 - listenToOnce with space-separated events', function(assert) {
assert.expect(2);
var one = _.extend({}, Backbone.Events);
var two = _.extend({}, Backbone.Events);
var count = 1;
one.listenToOnce(two, 'x y', function(n) { assert.ok(n === count++); });
two.trigger('x', 1);
two.trigger('x', 1);
two.trigger('y', 2);
two.trigger('y', 2);
});
})();

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,13 @@
(function() {
QUnit.module('Backbone.noConflict');
QUnit.test('noConflict', function(assert) {
assert.expect(2);
var noconflictBackbone = Backbone.noConflict();
assert.equal(window.Backbone, undefined, 'Returned window.Backbone');
window.Backbone = noconflictBackbone;
assert.equal(window.Backbone, noconflictBackbone, 'Backbone is still pointing to the original Backbone');
});
})();

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,4 @@
$('body').append(
'<div id="qunit"></div>' +
'<div id="qunit-fixture"></div>'
);

View file

@ -0,0 +1,45 @@
(function() {
var sync = Backbone.sync;
var ajax = Backbone.ajax;
var emulateHTTP = Backbone.emulateHTTP;
var emulateJSON = Backbone.emulateJSON;
var history = window.history;
var pushState = history.pushState;
var replaceState = history.replaceState;
QUnit.config.noglobals = true;
QUnit.testStart(function() {
var env = QUnit.config.current.testEnvironment;
// We never want to actually call these during tests.
history.pushState = history.replaceState = function(){};
// Capture ajax settings for comparison.
Backbone.ajax = function(settings) {
env.ajaxSettings = settings;
};
// Capture the arguments to Backbone.sync for comparison.
Backbone.sync = function(method, model, options) {
env.syncArgs = {
method: method,
model: model,
options: options
};
sync.apply(this, arguments);
};
});
QUnit.testDone(function() {
Backbone.sync = sync;
Backbone.ajax = ajax;
Backbone.emulateHTTP = emulateHTTP;
Backbone.emulateJSON = emulateJSON;
history.pushState = pushState;
history.replaceState = replaceState;
});
})();

View file

@ -0,0 +1,239 @@
(function() {
var Library = Backbone.Collection.extend({
url: function() { return '/library'; }
});
var library;
var attrs = {
title: 'The Tempest',
author: 'Bill Shakespeare',
length: 123
};
QUnit.module('Backbone.sync', {
beforeEach: function(assert) {
library = new Library;
library.create(attrs, {wait: false});
},
afterEach: function(assert) {
Backbone.emulateHTTP = false;
}
});
QUnit.test('read', function(assert) {
assert.expect(4);
library.fetch();
assert.equal(this.ajaxSettings.url, '/library');
assert.equal(this.ajaxSettings.type, 'GET');
assert.equal(this.ajaxSettings.dataType, 'json');
assert.ok(_.isEmpty(this.ajaxSettings.data));
});
QUnit.test('passing data', function(assert) {
assert.expect(3);
library.fetch({data: {a: 'a', one: 1}});
assert.equal(this.ajaxSettings.url, '/library');
assert.equal(this.ajaxSettings.data.a, 'a');
assert.equal(this.ajaxSettings.data.one, 1);
});
QUnit.test('create', function(assert) {
assert.expect(6);
assert.equal(this.ajaxSettings.url, '/library');
assert.equal(this.ajaxSettings.type, 'POST');
assert.equal(this.ajaxSettings.dataType, 'json');
var data = JSON.parse(this.ajaxSettings.data);
assert.equal(data.title, 'The Tempest');
assert.equal(data.author, 'Bill Shakespeare');
assert.equal(data.length, 123);
});
QUnit.test('update', function(assert) {
assert.expect(7);
library.first().save({id: '1-the-tempest', author: 'William Shakespeare'});
assert.equal(this.ajaxSettings.url, '/library/1-the-tempest');
assert.equal(this.ajaxSettings.type, 'PUT');
assert.equal(this.ajaxSettings.dataType, 'json');
var data = JSON.parse(this.ajaxSettings.data);
assert.equal(data.id, '1-the-tempest');
assert.equal(data.title, 'The Tempest');
assert.equal(data.author, 'William Shakespeare');
assert.equal(data.length, 123);
});
QUnit.test('update with emulateHTTP and emulateJSON', function(assert) {
assert.expect(7);
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, {
emulateHTTP: true,
emulateJSON: true
});
assert.equal(this.ajaxSettings.url, '/library/2-the-tempest');
assert.equal(this.ajaxSettings.type, 'POST');
assert.equal(this.ajaxSettings.dataType, 'json');
assert.equal(this.ajaxSettings.data._method, 'PUT');
var data = JSON.parse(this.ajaxSettings.data.model);
assert.equal(data.id, '2-the-tempest');
assert.equal(data.author, 'Tim Shakespeare');
assert.equal(data.length, 123);
});
QUnit.test('update with just emulateHTTP', function(assert) {
assert.expect(6);
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, {
emulateHTTP: true
});
assert.equal(this.ajaxSettings.url, '/library/2-the-tempest');
assert.equal(this.ajaxSettings.type, 'POST');
assert.equal(this.ajaxSettings.contentType, 'application/json');
var data = JSON.parse(this.ajaxSettings.data);
assert.equal(data.id, '2-the-tempest');
assert.equal(data.author, 'Tim Shakespeare');
assert.equal(data.length, 123);
});
QUnit.test('update with just emulateJSON', function(assert) {
assert.expect(6);
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, {
emulateJSON: true
});
assert.equal(this.ajaxSettings.url, '/library/2-the-tempest');
assert.equal(this.ajaxSettings.type, 'PUT');
assert.equal(this.ajaxSettings.contentType, 'application/x-www-form-urlencoded');
var data = JSON.parse(this.ajaxSettings.data.model);
assert.equal(data.id, '2-the-tempest');
assert.equal(data.author, 'Tim Shakespeare');
assert.equal(data.length, 123);
});
QUnit.test('read model', function(assert) {
assert.expect(3);
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
library.first().fetch();
assert.equal(this.ajaxSettings.url, '/library/2-the-tempest');
assert.equal(this.ajaxSettings.type, 'GET');
assert.ok(_.isEmpty(this.ajaxSettings.data));
});
QUnit.test('destroy', function(assert) {
assert.expect(3);
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
library.first().destroy({wait: true});
assert.equal(this.ajaxSettings.url, '/library/2-the-tempest');
assert.equal(this.ajaxSettings.type, 'DELETE');
assert.equal(this.ajaxSettings.data, null);
});
QUnit.test('destroy with emulateHTTP', function(assert) {
assert.expect(3);
library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'});
library.first().destroy({
emulateHTTP: true,
emulateJSON: true
});
assert.equal(this.ajaxSettings.url, '/library/2-the-tempest');
assert.equal(this.ajaxSettings.type, 'POST');
assert.equal(JSON.stringify(this.ajaxSettings.data), '{"_method":"DELETE"}');
});
QUnit.test('urlError', function(assert) {
assert.expect(2);
var model = new Backbone.Model();
assert.raises(function() {
model.fetch();
});
model.fetch({url: '/one/two'});
assert.equal(this.ajaxSettings.url, '/one/two');
});
QUnit.test('#1052 - `options` is optional.', function(assert) {
assert.expect(0);
var model = new Backbone.Model();
model.url = '/test';
Backbone.sync('create', model);
});
QUnit.test('Backbone.ajax', function(assert) {
assert.expect(1);
Backbone.ajax = function(settings){
assert.strictEqual(settings.url, '/test');
};
var model = new Backbone.Model();
model.url = '/test';
Backbone.sync('create', model);
});
QUnit.test('Call provided error callback on error.', function(assert) {
assert.expect(1);
var model = new Backbone.Model;
model.url = '/test';
Backbone.sync('read', model, {
error: function() { assert.ok(true); }
});
this.ajaxSettings.error();
});
QUnit.test('Use Backbone.emulateHTTP as default.', function(assert) {
assert.expect(2);
var model = new Backbone.Model;
model.url = '/test';
Backbone.emulateHTTP = true;
model.sync('create', model);
assert.strictEqual(this.ajaxSettings.emulateHTTP, true);
Backbone.emulateHTTP = false;
model.sync('create', model);
assert.strictEqual(this.ajaxSettings.emulateHTTP, false);
});
QUnit.test('Use Backbone.emulateJSON as default.', function(assert) {
assert.expect(2);
var model = new Backbone.Model;
model.url = '/test';
Backbone.emulateJSON = true;
model.sync('create', model);
assert.strictEqual(this.ajaxSettings.emulateJSON, true);
Backbone.emulateJSON = false;
model.sync('create', model);
assert.strictEqual(this.ajaxSettings.emulateJSON, false);
});
QUnit.test('#1756 - Call user provided beforeSend function.', function(assert) {
assert.expect(4);
Backbone.emulateHTTP = true;
var model = new Backbone.Model;
model.url = '/test';
var xhr = {
setRequestHeader: function(header, value) {
assert.strictEqual(header, 'X-HTTP-Method-Override');
assert.strictEqual(value, 'DELETE');
}
};
model.sync('delete', model, {
beforeSend: function(_xhr) {
assert.ok(_xhr === xhr);
return false;
}
});
assert.strictEqual(this.ajaxSettings.beforeSend(xhr), false);
});
QUnit.test('#2928 - Pass along `textStatus` and `errorThrown`.', function(assert) {
assert.expect(2);
var model = new Backbone.Model;
model.url = '/test';
model.on('error', function(m, xhr, options) {
assert.strictEqual(options.textStatus, 'textStatus');
assert.strictEqual(options.errorThrown, 'errorThrown');
});
model.fetch();
this.ajaxSettings.error({}, 'textStatus', 'errorThrown');
});
})();

View file

@ -0,0 +1,495 @@
(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);
});
})();