UNPKG

compose

Version:

Fast and light object composition based on mixins and traits

355 lines (345 loc) 8.81 kB
var assert = require("assert"), Compose = require("../compose"), required = Compose.required, around = Compose.around, from = Compose.from, create = Compose.create, Widget, MessageWidget, SpanishWidget; exports.testCompose = function() { Widget = Compose({ render: function(node){ node.innerHTML = "<div>hi</div>"; } }); var node = {}; var widget = new Widget(); widget.render(node); assert.equal(node.innerHTML, "<div>hi</div>"); }; exports.testComposeWithConstruct = function() { Widget = Compose(function(node){ this.node = node; },{ render: function(){ this.node.innerHTML = "<div>hi</div>"; }, getNode: function(){ return this.node; } }); var node = {}; var widget = new Widget(node); widget.render(); assert.equal(node.innerHTML, "<div>hi</div>"); }; exports.testInheritance = function() { MessageWidget = Compose(Widget, { message: "Hello, World", render: function(){ this.node.innerHTML = "<div>" + this.message + "</div>"; } }); var node = {}; var widget = new MessageWidget(node); widget.render(); assert.equal(node.innerHTML, "<div>Hello, World</div>"); }; exports.testInheritanceViaExtend = function() { MessageWidget = Widget.extend({ message: "Hello, World", render: function(){ this.node.innerHTML = "<div>" + this.message + "</div>"; } }); var node = {}; var widget = new MessageWidget(node); widget.render(); assert.equal(node.innerHTML, "<div>Hello, World</div>"); }; exports.testInheritance2 = function() { SpanishWidget = Compose(MessageWidget, { message: "Hola", }); var node = {}; var widget = new SpanishWidget(node); widget.render(); assert.equal(node.innerHTML, "<div>Hola</div>"); }; exports.testMultipleInheritance = function() { var Renderer = Compose(Widget, { render: function(){ this.node.innerHTML = "test" } }); var RendererSpanishWidget = Compose(Renderer, SpanishWidget); var SpanishWidgetRenderer = Compose(SpanishWidget, Renderer); var EmptyWidget = Compose(Widget,{}); var MessageWidget2 = Compose(MessageWidget, EmptyWidget); var node = {}; var widget = new RendererSpanishWidget(node); assert["throws"](function(){ widget.render(); // should throw conflicted error }); var widget = new SpanishWidgetRenderer(node); widget.render(); assert.equal(node.innerHTML, "test"); assert.equal(widget.getNode(), node); var widget = new MessageWidget2(node); widget.render(); assert.equal(node.innerHTML, "<div>Hello, World</div>"); }; exports.testAround = function() { var WithTitleWidget = Compose(MessageWidget, { message: "Hello, World", render: around(function(baseRender){ return function(){ baseRender.apply(this); node.innerHTML = "<hi>Title</h1>" + node.innerHTML; } }) }); var node = {}; var widget = new WithTitleWidget(node); widget.render(); assert.equal(node.innerHTML, "<hi>Title</h1><div>Hello, World</div>"); }; exports.testRequired = function() { var logged; var Logger = Compose({ logAndRender: function(){ logged = true; this.render(); }, render: required }); var LoggerMessageWidget = Compose(Logger, MessageWidget); var node = {}; var widget = new LoggerMessageWidget(node); widget.logAndRender(); assert.equal(node.innerHTML, "<div>Hello, World</div>"); assert.equal(logged, true); var MessageWidgetLogger = Compose(MessageWidget, Logger); var node = {}; var widget = new MessageWidgetLogger(node); widget.logAndRender(); assert.equal(node.innerHTML, "<div>Hello, World</div>"); assert.equal(logged, true); var widget = new Logger(node); assert["throws"](function(){ widget.render(); }); }; exports.testCreate = function() { var widget = Compose.create({ render: function(node){ node.innerHTML = "<div>hi</div>"; } }); var node = {}; widget.render(node); assert.equal(node.innerHTML, "<div>hi</div>"); }; exports.testInheritanceCreate= function() { var widget = Compose.create(Widget, { message: "Hello, World", render: function(){ this.node.innerHTML = "<div>" + this.message + "</div>"; } }, {foo: "bar"}); widget.node = {}; widget.render(); assert.equal(widget.node.innerHTML, "<div>Hello, World</div>"); assert.equal(widget.foo, "bar"); }; exports.testNestedCompose = function() { var ComposingWidget = Compose(Compose, { foo: "bar" }); var widget = ComposingWidget({ bar: "foo" }); assert.equal(widget.foo, "bar"); assert.equal(widget.bar, "foo"); }; exports.testFromAlias = function() { var AliasedWidget = Compose(Widget, MessageWidget, { baseRender: from(Widget, "render"), messageRender: from("render"), render: function(){ this.baseRender(); var base = this.node.innerHTML; this.messageRender(); var message = this.node.innerHTML; this.node.innerHTML = base + message; } }); var node = {}; var widget = new AliasedWidget(node); widget.render(node); assert.equal(node.innerHTML, "<div>hi</div><div>Hello, World</div>"); }; exports.testFromExclude = function() { var ExcludeWidget = Compose(Widget, MessageWidget, { render: from(Widget) }); var node = {}; var widget = new ExcludeWidget(node); widget.render(); assert.equal(node.innerHTML, "<div>hi</div>"); }; exports.testComplexHierarchy = function(){ var order = []; var Widget = Compose( function(args){ this.id = args.id; }, { render: function(){ order.push(1); } } ); var SubMixin1 = Compose( { render: Compose.after(function(){ order.push(2); }) } ); var SubMixin2 = Compose( function(args){ }, { render: Compose.after(function(){ order.push(3); }) } ); var Mixin = Compose(SubMixin1, SubMixin2, { render: Compose.after(function(){ order.push(4); }) } ); var Mixin2 = Compose( { render: around(function(baseRender){ return function(){ baseRender.apply(this, arguments); order.push(5); }; }) } ); var Button = Compose(Widget, Mixin, Mixin2, function(args){ }, { render: Compose.around(function(baseRender){ return function(){ baseRender.apply(this, arguments); order.push(6); }; }) } ); var myButton = new Button({id: "myId"}); myButton.render(); assert.deepEqual(order, [1,2,3,4,5,6]); }; exports.testExtendError = function(){ var CustomError = Compose(Error, { name: "CustomError" }); var error = new CustomError("test"); assert.equal(error.name, "CustomError"); assert.equal(error.toString(), "CustomError: test"); assert.equal(error instanceof CustomError, true); assert.equal(error instanceof Error, true); } exports.testDiamond = function(){ var baseCallCount = 0, sub1CallCount = 0, sub2CallCount = 0, fooCallCount = 0, fooSub1Count = 0, fooSub2Count = 0; var Base = Compose(function(){ baseCallCount++; }, { foo: function(){ fooCallCount++; } }); var Sub1 = Compose(Base, function(){sub1CallCount++;}, { foo: Compose.after(function(){ fooSub1Count++; }) }); var Sub2 = Compose(Base, function(){sub2CallCount++;}, { foo: Compose.after(function(){ fooSub2Count++; }) }); var Combined = Sub1.extend(Sub2); var combined = new Combined; assert.equal(baseCallCount, 1); assert.equal(sub1CallCount, 1); assert.equal(sub2CallCount, 1); combined.foo(); assert.equal(fooCallCount, 1); //assert.equal(fooSub1Count, 1); // TODO: Should this be 1? assert.equal(fooSub2Count, 1); } exports.testNull = function() { var errored; try{ Compose(null, {}); }catch(e){ errored = true; } assert.equal(errored, true); } exports.testAdvice = function() { var order = []; var obj = { foo: function(value){ order.push(value); return 6; }, }; Advised = Compose(obj, { "foo": Compose.around(function(base){ return function(){ order.push(2); try{ return base.apply(this, arguments); }finally{ order.push(4); } } }) }); Advised = Compose(Advised, { "foo": Compose.after(function(){ order.push(5); }) }); Advised = Compose(Advised, { "foo": Compose.before(function(value){ order.push(value); return [3]; }) }); obj = new Advised(); order.push(obj.foo(1)); assert.deepEqual(order, [1,2,3,4,5,6]); order = []; Advised = Compose(Advised, { "foo": Compose.before(function(value){ order.push(0); return Compose.stop; }) }); obj = new Advised(); obj.foo(1); assert.deepEqual(order, [0]); }; if (require.main === module) require("patr/runner").run(exports);