UNPKG

hermes-bus

Version:

Powerful event-emitter module for responsive bus architecture applications

551 lines (446 loc) 24.2 kB
/** * hermes-bus <https://github.com/jahnestacado/hermes-bus> * Copyright (c) 2014 Ioannis Tzanellis * Licensed under the MIT License (MIT). */ var assert = require("assert"); var bus = require("./.."); var sinon = require("sinon"); var _ = require("underscore"); describe('#################### Start integration tests for hermes-bus module \n', function() { describe("trigger events", function() { var firstEventCallback = sinon.spy(); var secondEventCallback = sinon.spy(); describe("when triggering 'firstEvent'", function() { var firstEventArg1 = {isDummy: true}; var firstEventArg2 = "foo"; var firstEventArg3 = 639; before(function(){ bus.subscribe({ onFirstEvent: firstEventCallback, onSecondEvent: secondEventCallback }); }); before(function() { bus.trigger("firstEvent", firstEventArg1, firstEventArg2, firstEventArg3); }); it("should have 'firstEvent' attached", function() { assert(bus.hasEvent("firstEvent")); }); it("should have 'secondEvent' attached", function() { assert(bus.hasEvent("secondEvent")); }); it("should invoke firstCallback once", function() { assert(firstEventCallback.calledOnce); }); it("should invoke firstCallback with the right argument", function() { assert(firstEventCallback.calledWith(firstEventArg1, firstEventArg2, firstEventArg3)); }); it("should not invoke secondCallback", function() { assert(firstEventCallback.calledOnce, false); }); describe("when invoking bus.triggerSecondEvent", function() { var secondEventArg1 = {isDummy: true}; var secondEventArg2 = [3, 5, 6, ["4"]]; before(function() { bus.triggerSecondEvent(firstEventArg1, secondEventArg2); }); it("should invoke secondCallback once", function() { assert(secondEventCallback.calledOnce); }); it("should invoke secondCallback with the right argument", function() { assert(secondEventCallback.calledWith(secondEventArg1, secondEventArg2)); }); it("should not invoke firstCallback again", function() { assert(firstEventCallback.calledOnce); }); describe("creating 'red busline' ", function() { var thirdEventCallback = sinon.spy(); before(function() { bus.subscribe("red",{ onFirstEvent:thirdEventCallback }); }); describe("when triggering 'firstEvent' on the red busline", function() { var thirdEventArg1 = {isDummy: true}; before(function() { bus.red.trigger("firstEvent", thirdEventArg1); }); it("should have 'firstEvent' attached on the red busline", function() { assert(bus.red.hasEvent("firstEvent")); }); it("should invoke thirdCallback once", function() { assert(thirdEventCallback.calledOnce); }); it("should invoke thirdCallback with the right argument", function() { assert(thirdEventCallback.calledWith(thirdEventArg1)); }); it("should not invoke firstCallback again", function() { assert(firstEventCallback.calledOnce); }); it("should not invoke secondCallback again", function() { assert(secondEventCallback.calledOnce); }); describe("when disabling and invoking triggerFirstEvent on the red busline", function() { before(function() { bus.red.disable("firstEvent"); }); before(function() { bus.red.trigger("firstEvent"); }); it("should still have 'firstEvent' attached on the red busline", function() { assert(bus.red.hasEvent("firstEvent")); }); it("should not invoke firstCallback again", function() { assert(firstEventCallback.calledOnce); }); it("should not invoke thirdCallback again", function() { assert(thirdEventCallback.calledOnce); }); it("should not invoke secondCallback again", function() { assert(secondEventCallback.calledOnce); }); describe("when re-enabling and triggering 'thirdEvent' on the red busline", function() { before(function() { bus.red.enable("firstEvent"); bus.red.trigger("firstEvent"); }); it("should invoke thirdCallback for second time", function() { assert(thirdEventCallback.calledTwice); }); it("should not invoke firstCallback again", function() { assert(firstEventCallback.calledOnce); }); it("should not invoke secondCallback again", function() { assert(secondEventCallback.calledOnce); }); }); describe("when creating 'green' and 'black' and 'white' buslines", function() { var dummyEventCallback = sinon.spy(); before(function() { bus.subscribe("green",{ onDummyEvent: dummyEventCallback }); bus.subscribe("black",{ onDummyEvent: dummyEventCallback }); }); it("should have 'green' busline", function() { assert(bus.green); }); it("should have 'dummyEvent' attached on the green busline", function() { assert(bus.green.hasEvent("dummyEvent")); }); it("should have 'black' busline", function() { assert(bus.black); }); it("should have 'dummyEvent' attached on the black busline", function() { assert(bus.black.hasEvent("dummyEvent")); }); describe("when invoking reset on 'main' busline", function() { before(function() { bus.reset(); }); it("should not have 'dummyEvent' attached on the green busline", function() { assert(bus.green.hasEvent("dummyEvent"), false); }); it("should not have 'dummyEvent' attached on the black busline", function() { assert(bus.black.hasEvent("dummyEvent"), false); }); it("should not have triggerFirstEvent function on 'main' busline", function() { assert.equal(bus.triggerFirstEvent, undefined); }); it("should not have triggerSecondEvent function on 'main' busline", function() { assert.equal(bus.triggerSecondEvent, undefined); }); it("should maintain 'red' busline", function() { assert(bus.red); }); it("should maintain 'green' busline", function() { assert(bus.green); }); describe("when invoking destroy on 'red' busline", function() { before(function() { bus.red.destroy(); }); it("should destroy 'red' busline", function() { assert.equal(bus.red, undefined); }); describe("when invoking hardReset on 'main' busline", function() { before(function() { bus.hardReset(); }); it("should destroy 'green' busline", function() { assert.equal(bus.green, undefined); }); it("should destroy 'white' busline", function() { assert.equal(bus.green, undefined); }); describe("when creating again 'dummyEvent' message on 'green' busline ", function() { before(function() { bus.subscribe("green",{ onDummyEvent: dummyEventCallback }); }); it("should not have invoked 'dummyEventCallback' until this point", function() { assert.equal(dummyEventCallback.called, false); }); describe("when triggering 'dummyEvent' message on 'green' busline ", function() { before(function() { bus.green.trigger("dummyEvent"); }); it("should invoke 'dummyEventCallback' only once", function() { assert(dummyEventCallback.calledOnce); }); }); }); }); }); }); }); }); }); }); }); }); describe("when resolving events", function() { function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function add1567(x) { return x + 1567; } function mul45(x) { return x * 45; } function div3(x) { return x / 3; } function getAsyncApplyOperationFunc(operation) { return function asyncFunc(refObject, resolve) { setTimeout(function() { refObject.value = operation(refObject.value); resolve(); }, getRandomInt(300)); }; } var firstEventCallback = sinon.spy(getAsyncApplyOperationFunc(add1567)); var secondEventCallback = sinon.spy(getAsyncApplyOperationFunc(mul45)); var thirdEventCallback = sinon.spy(getAsyncApplyOperationFunc(div3)); describe("when registering events", function() { before(function() { bus.subscribe({ __onForthEvent: firstEventCallback }); bus.subscribe({ __onForthEvent: secondEventCallback }); bus.subscribe({ __onForthEvent: thirdEventCallback }); }); describe("when invoking bus.triggerForthEvent while event is disabled", function() { var results = {value: 10}; before(function() { bus.disable("forthEvent"); }); before(function() { bus.triggerForthEvent(results); }); it("should not invoke firstEventCallback", function() { assert(firstEventCallback.notCalled); }); it("should not invoke secondEventCallback", function() { assert(secondEventCallback.notCalled); }); it("should not invoke thirdEventCallback", function() { assert(thirdEventCallback.notCalled); }); before(function() { bus.enable("forthEvent"); }); }); describe("when invoking bus.triggerForthEvent with use of .then()", function() { var results = {value: 10}; before(function(done) { bus.trigger("forthEvent", results).then(function() { done(); }); }); it("should have calculated all math operation in order", function() { assert(results.value === 23655); }); it("should invoke firstEventCallback once", function() { assert(firstEventCallback.calledOnce); }); it("should invoke secondEventCallback once", function() { assert(secondEventCallback.calledOnce); }); it("should invoke thirdEventCallback once", function() { assert(thirdEventCallback.calledOnce); }); it("should invoke firstEventCallback with the right arguments", function() { assert(firstEventCallback.calledWith(results)); }); it("should invoke secondEventCallback with the right arguments", function() { assert(secondEventCallback.calledWith(results)); }); it("should invoke thirdEventCallback with the right arguments", function() { assert(thirdEventCallback.calledWith(results)); }); }); describe("when testing the before/after hooks", function() { var result = {text:""}; var createAppender = function(keyword){ return function(text, symbol){result.text += keyword + symbol;}; }; var firstBeforeCallback = sinon.spy(createAppender("before1")); var secondBeforeCallback = sinon.spy(createAppender("before2")); var firstEventCallback = sinon.spy(createAppender("on1")); var secondEventCallback = sinon.spy(createAppender("on2")); var firstAfterCallback = sinon.spy(createAppender("after1")); var secondAfterCallback = sinon.spy(createAppender("after2")); before(function() { bus.subscribe({ beforeHookTest: firstBeforeCallback, onHookTest: firstEventCallback, afterHookTest: firstAfterCallback }); bus.subscribe({ beforeHookTest: secondBeforeCallback, onHookTest: secondEventCallback, afterHookTest: secondAfterCallback }); }); before(function() { bus.trigger("hookTest", result, "-"); }); it("should append all substrings in order and create the expected string", function(){ assert(result.text === "before1-before2-on1-on2-after1-after2-"); }); }); }); }); describe("when testing the unsubscribe function", function(){ var subscribedObjectA = { beforeFoo: sinon.stub(), onFoo: sinon.stub(), afterFoo: sinon.stub() }; var subscribedObjectB = { beforeFoo: sinon.stub(), onFoo: sinon.stub(), afterFoo: sinon.stub() }; before(function(){ bus.subscribe("red", subscribedObjectA); bus.subscribe("red", subscribedObjectB); }); describe("when triggering the foo event", function(){ before(function(){ bus.red.triggerFoo(); }); after(function(){ bus.hardReset(); }); it("should trigger the subscribedObjectA.beforeFoo listener stub once", function(){ sinon.assert.calledOnce(subscribedObjectA.beforeFoo); }); it("should trigger the subscribedObjectA.onFoo listener stub once", function(){ sinon.assert.calledOnce(subscribedObjectA.onFoo); }); it("should trigger the subscribedObjectA.afterFoo listener stub once", function(){ sinon.assert.calledOnce(subscribedObjectA.afterFoo); }); it("should trigger the subscribedObjectB.beforeFoo listener stub once", function(){ sinon.assert.calledOnce(subscribedObjectB.beforeFoo); }); it("should trigger the subscribedObjectB.onFoo listener stub once", function(){ sinon.assert.calledOnce(subscribedObjectB.onFoo); }); it("should trigger the subscribedObjectB.afterFoo listener stub once", function(){ sinon.assert.calledOnce(subscribedObjectB.afterFoo); }); describe("when unsubscribing 'subscribedObjectA' and triggering foo event again", function(){ before(function(){ bus.unsubscribe("red", subscribedObjectA); }); before(function(){ bus.red.triggerFoo(); }); it("should not trigger the subscribedObjectA.beforeFoo listener stub again", function(){ sinon.assert.calledOnce(subscribedObjectA.beforeFoo); }); it("should not trigger the subscribedObjectA.onFoo listener stub again", function(){ sinon.assert.calledOnce(subscribedObjectA.onFoo); }); it("should not trigger the subscribedObjectA.afterFoo listener stub again", function(){ sinon.assert.calledOnce(subscribedObjectA.afterFoo); }); it("should trigger the subscribedObjectB.beforeFoo listener stub twice", function(){ sinon.assert.calledTwice(subscribedObjectB.beforeFoo); }); it("should trigger the subscribedObjectB.onFoo listener stub twice", function(){ sinon.assert.calledTwice(subscribedObjectB.onFoo); }); it("should trigger the subscribedObjectB.afterFoo listener stub twice", function(){ sinon.assert.calledTwice(subscribedObjectB.afterFoo); }); }); }); }); describe("when testing the non-overridable properties", function(){ var nonOverridableProps = _.union(["$main_busline$"], Object.keys(Object.getPrototypeOf(bus)), Object.keys(bus)); nonOverridableProps.forEach(function(propertyName){ it("should throw the expected error", function(){ assert.throws(function(){ bus.subscribe(propertyName, {}) }, function(error){ if(error.message === "Not permitted busline name: " + propertyName + ". Cannot override API functions: [ "+ nonOverridableProps +"]."){ return true; } }); }); }); }); describe("when an event is throwing an exception", function(){ var value = 0; var theError = new Error("The Error!"); before(function(){ sinon.spy(console, "error"); }); after(function(){ console.error.restore(); }) before(function(){ bus.subscribe({ onException: function(){throw theError}, }); bus.subscribe({ onUpdateValue: function(newValue){ value = newValue; }, }); }); after(function(){ bus.hardReset(); }); before(function(){ bus.triggerException(); bus.triggerUpdateValue(100); }); it("should not affect the execution of other events (e.g 'updateValue') and set the value variable to 100", function() { assert.equal(value, 100); }); it("should call console.error once with expected arguments", function() { sinon.assert.calledOnce(console.error); sinon.assert.calledWithExactly(console.error, "[ERROR][Hermes-bus] Exception thrown from within a listener" + " (e.g beforeException, onException or afterException) ->", theError); }); }); after(function() { console.log("\n #################### End of integration tests for hermes-bus module."); }); }); });