describe("Class", function () { describe("#extend", function () { var Klass, constructor, method; beforeEach(function () { constructor = sinon.spy(); method = sinon.spy(); Klass = L.Class.extend({ statics: {bla: 1}, includes: {mixin: true}, initialize: constructor, foo: 5, bar: method }); }); it("creates a class with the given constructor & properties", function () { var a = new Klass(); expect(constructor.called).to.be.ok(); expect(a.foo).to.eql(5); a.bar(); expect(method.called).to.be.ok(); }); it("inherits parent classes' constructor & properties", function () { var Klass2 = Klass.extend({baz: 2}); var b = new Klass2(); expect(b instanceof Klass).to.be.ok(); expect(b instanceof Klass2).to.be.ok(); expect(constructor.called).to.be.ok(); expect(b.baz).to.eql(2); b.bar(); expect(method.called).to.be.ok(); }); it("supports static properties", function () { expect(Klass.bla).to.eql(1); }); it("inherits parent static properties", function () { var Klass2 = Klass.extend({}); expect(Klass2.bla).to.eql(1); }); it("overrides parent static properties", function () { var Klass2 = Klass.extend({statics: {bla: 2}}); expect(Klass2.bla).to.eql(2); }); it("includes the given mixin", function () { var a = new Klass(); expect(a.mixin).to.be.ok(); }); it("includes multiple mixins", function () { var Klass2 = L.Class.extend({ includes: [{mixin: true}, {mixin2: true}] }); var a = new Klass2(); expect(a.mixin).to.be.ok(); expect(a.mixin2).to.be.ok(); }); it("grants the ability to include the given mixin", function () { Klass.include({mixin2: true}); var a = new Klass(); expect(a.mixin2).to.be.ok(); }); it("merges options instead of replacing them", function () { var KlassWithOptions1 = L.Class.extend({ options: { foo1: 1, foo2: 2 } }); var KlassWithOptions2 = KlassWithOptions1.extend({ options: { foo2: 3, foo3: 4 } }); var a = new KlassWithOptions2(); expect(a.options.foo1).to.eql(1); expect(a.options.foo2).to.eql(3); expect(a.options.foo3).to.eql(4); }); it("gives new classes a distinct options object", function () { var K1 = L.Class.extend({options: {}}); var K2 = K1.extend({}); expect(K2.prototype.options).not.to.equal(K1.prototype.options); }); it("inherits options prototypally", function () { var K1 = L.Class.extend({options: {}}); var K2 = K1.extend({options: {}}); K1.prototype.options.foo = 'bar'; expect(K2.prototype.options.foo).to.eql('bar'); }); it("adds constructor hooks correctly", function () { var spy1 = sinon.spy(); Klass.addInitHook(spy1); Klass.addInitHook('bar', 1, 2, 3); var a = new Klass(); expect(spy1.called).to.be.ok(); expect(method.calledWith(1, 2, 3)); }); it("inherits constructor hooks", function () { var spy1 = sinon.spy(), spy2 = sinon.spy(); var Klass2 = Klass.extend({}); Klass.addInitHook(spy1); Klass2.addInitHook(spy2); var a = new Klass2(); expect(spy1.called).to.be.ok(); expect(spy2.called).to.be.ok(); }); it("does not call child constructor hooks", function () { var spy1 = sinon.spy(), spy2 = sinon.spy(); var Klass2 = Klass.extend({}); Klass.addInitHook(spy1); Klass2.addInitHook(spy2); var a = new Klass(); expect(spy1.called).to.be.ok(); expect(spy2.called).to.eql(false); }); it("calls parent constructor hooks when child has none", function () { var spy1 = sinon.spy(); Klass.addInitHook(spy1); var Klass2 = Klass.extend({}); var a = new Klass2(); expect(spy1.called).to.be.ok(); }); }); describe("#include", function () { var Klass; beforeEach(function () { Klass = L.Class.extend({}); }); it("returns the class with the extra methods", function () { var q = sinon.spy(); var Qlass = Klass.include({quux: q}); var a = new Klass(); var b = new Qlass(); a.quux(); expect(q.called).to.be.ok(); b.quux(); expect(q.called).to.be.ok(); }); }); // TODO Class.mergeOptions });