spritzr
Version:
Provides an inheritance/traits/talents library
551 lines (376 loc) • 12.8 kB
JavaScript
var Spritzr = require("../../src/Spritzr.js");
describe("Spritzr", function() {
describe("Inheritance", function() {
it("can extend a class", function() {
var SuperClass = function() {};
SuperClass.prototype.method1 = function() {
return "method1";
};
var SubClass = function() {};
Spritzr.extend(SubClass, SuperClass);
var instance = new SubClass();
expect(instance.method1()).toBe("method1");
});
it("maintains the prototype chain", function() {
var SuperSuperClass = function() {};
var SuperClass = function() {};
Spritzr.extend(SuperClass, SuperSuperClass);
var SubClass = function() {};
Spritzr.extend(SubClass, SuperClass);
var test = new SubClass();
expect(test instanceof SubClass).toBe(true);
expect(test instanceof SuperClass).toBe(true);
expect(test instanceof SuperSuperClass).toBe(true);
expect(test instanceof String).toBe(false);
});
it("can call superclass constructor", function() {
var SuperClass = function SuperClass() {
this.test1 = "super";
this.test2 = "super";
};
SuperClass.prototype.test1 = "none";
SuperClass.prototype.test2 = "none";
var SubClass = function SubClass() {
this.$super();
this.test1 = "sub";
};
Spritzr.extend(SubClass, SuperClass);
var instance = new SubClass();
expect(instance.test1).toBe("sub");
expect(instance.test2).toBe("super");
});
it("can override a method", function() {
var SuperClass = function() {};
SuperClass.prototype.test = function() {
return 'super';
};
var SubClass = function() {};
Spritzr.extend(SubClass, SuperClass);
SubClass.prototype.test = function() {
return 'sub';
};
var test = new SubClass();
expect(test.test()).toBe('sub');
});
it("can access superclass methods", function() {
var SuperClass = function() {};
SuperClass.prototype.test = function() {
return 'super';
};
var SubClass = function() {
this.$super();
};
SubClass.prototype.test = function() {
return this.$super.test();
};
Spritzr.extend(SubClass, SuperClass);
var test = new SubClass();
expect(test.test()).toBe('super');
});
it("maintains existing protoype properties", function() {
var SuperClass = function() {};
var SubClass = function() {};
SubClass.prototype.method = function() {
return "sub";
};
Spritzr.extend(SubClass, SuperClass);
var instance = new SubClass();
expect(instance.method()).toBe("sub");
});
it("overrides existing protoype properties", function() {
var SuperClass = function() {};
SuperClass.prototype.method = function() {
return "super";
};
var SubClass = function() {};
SubClass.prototype.method = function() {
return "sub";
};
Spritzr.extend(SubClass, SuperClass);
var instance = new SubClass();
expect(instance.method()).toBe("sub");
});
it("allows superclass to access subclass properties", function() {
var SuperClass = function() {};
SuperClass.prototype.method = function() {
this.test = "super";
};
var SubClass = function() {
this.test = "sub";
};
SubClass.prototype.method = function() {
this.$super.method.call(this);
return this.test;
};
SubClass.prototype.test = null;
Spritzr.extend(SubClass, SuperClass);
var instance = new SubClass();
expect(instance.method()).toBe("super");
});
});
describe("Traits", function() {
it("can add a trait with a method to a class", function() {
var called = false;
var TestClass = function() {};
var Trait = function() {};
Trait.prototype.prop = false;
Trait.prototype.method = function() {
called = true;
};
Spritzr.spritz(TestClass, Trait);
var test = new TestClass();
test.method();
expect(called).toBe(true);
});
it("can add a trait with state to a class", function() {
var TestClass = function() {};
var Trait = function() {};
Trait.prototype.prop = false;
Trait.prototype.method = function() {
this.prop = true;
};
Spritzr.spritz(TestClass, Trait);
var test = new TestClass();
test.method();
expect(test.prop).toBe(true);
});
it('allows access to target property from trait method', function() {
var TestClass = function() {};
TestClass.prototype.test = 'test';
var Trait = function() {};
Trait.prototype.prop = false;
Trait.prototype.method = function() {
return this.test;
};
Spritzr.spritz(TestClass, Trait);
var test = new TestClass();
expect(test.method()).toBe('test');
});
it('allows access to trait property from target method', function() {
var TestClass = function() {};
TestClass.prototype.method = function() {
return this.test;
};
var Trait = function() {};
Trait.prototype.prop = false;
Trait.prototype.test = 'test';
Spritzr.spritz(TestClass, Trait);
var test = new TestClass();
expect(test.method()).toBe('test');
});
});
describe("Talents", function() {
it('can add a talent with a method to an instance', function() {
var TestClass = function() {};
var TestTalent = function() {};
TestTalent.prototype.method = function() {
return "test";
};
var test = new TestClass();
Spritzr.spritz(test, TestTalent);
expect(test.method()).toBe("test");
});
it('instantiates a talent if the talent is a class', function() {
var TestClass = function() {};
var TestTalent = function() {
this.talentInitialised = true;
};
var test = new TestClass();
Spritzr.spritz(test, TestTalent);
expect(test.talentInitialised).toBe(true);
});
it('can override class method with a talent', function() {
var TestClass = function() {};
TestClass.prototype.method = function() {
return "class";
}
var TestTalent = function() {};
TestTalent.prototype.method = function() {
return "talent";
};
var test = new TestClass();
Spritzr.spritz(test, TestTalent);
expect(test.method()).toBe("talent");
});
it('can remove a talent', function() {
var TestClass = function() {};
var TestTrait = function() {};
TestTrait.prototype.method = function() {
return "trait";
};
Spritzr.spritz(TestClass, TestTrait);
var TestTalent = function() {};
TestTalent.prototype.method = function() {
return "talent";
};
var test = new TestClass();
Spritzr.spritz(test, TestTalent);
Spritzr.unspritz(test, TestTalent);
expect(Spritzr.isa(test, TestTalent)).toBe(false);
});
it('reinstantes class method when talent removed', function() {
var TestClass = function() {};
TestClass.prototype.method = function() {
return "class";
};
var TestTalent = function() {};
TestTalent.prototype.method = function() {
return "talent";
};
var test = new TestClass();
Spritzr.spritz(test, TestTalent);
expect(test.method()).toBe("talent");
Spritzr.unspritz(test, TestTalent);
expect(test.method()).toBe("class");
});
it('reinstantes trait method when talent removed', function() {
var TestClass = function() {};
TestClass.prototype.method = function() {
return "class";
};
var TestTrait = function() {};
TestTrait.prototype.method = function() {
return "trait";
};
Spritzr.spritz(TestClass, TestTrait);
var TestTalent = function() {};
TestTalent.prototype.method = function() {
return "talent";
};
var test = new TestClass();
Spritzr.spritz(test, TestTalent);
expect(test.method()).toBe("talent");
Spritzr.unspritz(test, TestTalent);
expect(test.method()).toBe("trait");
});
it('reinstantes superclass method when talent removed', function() {
var SuperClass = function() {};
SuperClass.prototype.method = function() {
return "super";
};
var TestClass = function() {};
Spritzr.extend(TestClass, SuperClass);
var TestTalent = function() {};
TestTalent.prototype.method = function() {
return "talent";
};
var test = new TestClass();
Spritzr.spritz(test, TestTalent);
expect(test.method()).toBe("talent");
Spritzr.unspritz(test, TestTalent);
expect(test.method()).toBe("super");
});
it('reinstantes overridden talent methods', function() {
var TestClass = function TestClass() {};
var TestTalent1 = function TestTalent1() {};
TestTalent1.prototype.method = function() {
return "talent1";
};
var TestTalent2 = function TestTalent2() {};
TestTalent2.prototype.method = function() {
return "talent2";
};
var test = new TestClass();
Spritzr.spritz(test, TestTalent1);
Spritzr.spritz(test, TestTalent2);
expect(test.method()).toBe("talent2"); // Should be the last one added
Spritzr.unspritz(test, TestTalent2);
expect(test.method()).toBe("talent1");
});
it('doesn\'t mess with method if talent method not visible', function() {
var TestClass = function TestClass() {};
TestClass.prototype.method = function() {
return "class";
};
var TestTalent1 = function TestTalent1() {};
TestTalent1.prototype.method = function() {
return "talent1";
};
var TestTalent2 = function TestTalent2() {};
TestTalent2.prototype.method = function() {
return "talent2";
};
var test = new TestClass();
Spritzr.spritz(test, TestTalent1);
Spritzr.spritz(test, TestTalent2);
expect(test.method()).toBe("talent2"); // Should be the last one added
Spritzr.unspritz(test, TestTalent1);
expect(test.method()).toBe("talent2");
Spritzr.unspritz(test, TestTalent2);
expect(test.method()).toBe("class");
});
});
describe("isa() method", function() {
it('works for a given class', function() {
var TestClass = function() {};
var test = new TestClass();
expect(Spritzr.isa(test, TestClass)).toBe(true);
expect(Spritzr.isa(test, String)).toBe(false);
});
it('works for a super class', function() {
var SuperClass = function() {};
var SubClass = function() {};
Spritzr.extend(SubClass, SuperClass);
var test = new SubClass();
expect(Spritzr.isa(test, SuperClass)).toBe(true);
expect(Spritzr.isa(test, String)).toBe(false);
});
it('works for a trait in the given class', function() {
var TestClass = function() {};
var Trait = function() {};
Spritzr.spritz(TestClass, Trait);
var test = new TestClass();
expect(Spritzr.isa(test, Trait)).toBe(true);
expect(Spritzr.isa(test, String)).toBe(false);
});
it('works for a trait in the given super class', function() {
var SuperClass = function() {};
var Trait = function() {};
Spritzr.spritz(SuperClass, Trait);
var SubClass = function() {};
Spritzr.extend(SubClass, SuperClass);
var test = new SubClass();
expect(Spritzr.isa(test, Trait)).toBe(true);
expect(Spritzr.isa(test, String)).toBe(false);
});
it('works for a trait on a trait', function() {
var SuperTrait = function() {};
var Trait = function() {};
Spritzr.spritz(Trait, SuperTrait);
var SubClass = function() {};
Spritzr.spritz(SubClass, Trait);
var test = new SubClass();
expect(Spritzr.isa(test, SuperTrait)).toBe(true);
expect(Spritzr.isa(test, String)).toBe(false);
});
it('works for a superclass on a trait', function() {
var SuperClass = function() {};
var Trait = function() {};
Spritzr.extend(Trait, SuperClass);
var SubClass = function() {};
Spritzr.spritz(SubClass, Trait);
var test = new SubClass();
expect(Spritzr.isa(test, SuperClass)).toBe(true);
expect(Spritzr.isa(test, String)).toBe(false);
});
it('works for multiple traits', function() {
var Trait1 = function() {};
var Trait2 = function() {};
var SubClass = function() {};
Spritzr.spritz(SubClass, Trait1);
Spritzr.spritz(SubClass, Trait2);
var test = new SubClass();
expect(Spritzr.isa(test, Trait1)).toBe(true);
expect(Spritzr.isa(test, Trait2)).toBe(true);
expect(Spritzr.isa(test, String)).toBe(false);
});
it('works for a trait in the given instance', function() {
var TestClass = function() {};
var Talent = function() {};
var test = new TestClass();
Spritzr.spritz(test, Talent);
expect(Spritzr.isa(test, Talent)).toBe(true);
expect(Spritzr.isa(test, String)).toBe(false);
});
});
});