UNPKG

eventric

Version:

Build JavaScript applications with Behaviour-driven Domain Design. Based on DDD, BDD, CQRS and EventSourcing.

279 lines (199 loc) 9.32 kB
describe 'Remote Projection Feature', -> exampleContext = null beforeEach -> exampleContext = eventric.context 'Example' exampleContext.defineDomainEvents ExampleCreated: -> ExampleUpdated: -> exampleContext.addCommandHandlers CreateExample: (params, callback) -> @$repository('Example').create() .then (exampleId) => @$repository('Example').save exampleId .then (exampleId) -> callback null, exampleId UpdateExample: (params, callback) -> @$repository('Example').findById params.id .then (example) => example.update() @$repository('Example').save params.id .then -> callback() class Example create: (callback) -> @$emitDomainEvent 'ExampleCreated' callback() update: -> @$emitDomainEvent 'ExampleUpdated' exampleContext.addAggregate 'Example', Example exampleContext.initialize() .then -> exampleContext.enableWaitingMode() describe 'given we created and initialized some example context', -> describe 'when we add a projection to the remote', -> projectionId = null exampleRemote = null beforeEach -> exampleRemote = eventric.remote 'Example' class ExampleProjection initialize: (params, done) -> done() handleExampleCreated: (domainEvent) -> @created = true handleToCheckCorrectFunctionCall: (domainEvent) -> exampleRemote.addProjection 'ExampleProjection', ExampleProjection exampleRemote.initializeProjectionInstance 'ExampleProjection' .then (_projectionId) -> projectionId = _projectionId it 'then the projection should update its state as expected', -> exampleRemote.command 'CreateExample' .then -> exampleProjection = exampleRemote.getProjectionInstance projectionId expect(exampleProjection.created).to.be.true it 'then we should be able to remove it', -> sandbox.spy exampleRemote, 'unsubscribeFromDomainEvent' exampleRemote.destroyProjectionInstance projectionId expect(exampleRemote.getProjectionInstance projectionId).to.be.undefined expect(exampleRemote.unsubscribeFromDomainEvent).to.have.been.called describe 'when we initialize a projection as object on the remote', -> projectionId = null exampleRemote = null beforeEach -> exampleRemote = eventric.remote 'Example' exampleRemote.initializeProjection initialize: (params, done) -> done() handleExampleCreated: (domainEvent) -> @created = true handleToCheckCorrectFunctionCall: (domainEvent) -> .then (_projectionId) -> projectionId = _projectionId it 'then the projection should update its state as expected', -> exampleRemote.command 'CreateExample' .then -> exampleProjection = exampleRemote.getProjectionInstance projectionId expect(exampleProjection.created).to.be.true describe 'when we add a remote projection to the remote which subscribes to a specific aggregate', -> exampleRemote = null projectionId = null beforeEach -> exampleRemote = eventric.remote 'Example' class ExampleProjection initialize: (params, done) -> @$subscribeHandlersWithAggregateId params.aggregateId done() handleExampleUpdated: (domainEvent) -> @updated = true exampleRemote.addProjection 'ExampleProjection', ExampleProjection it 'then should update the remote projection as expected', -> testExampleId = null exampleRemote.command 'CreateExample' .then (exampleId) -> testExampleId = exampleId exampleRemote.initializeProjectionInstance 'ExampleProjection', aggregateId: exampleId .then (_projectionId) -> projectionId = _projectionId exampleRemote.command 'CreateExample' .then (exampleId) -> exampleRemote.command 'UpdateExample', id: exampleId .then -> exampleProjection = exampleRemote.getProjectionInstance projectionId expect(exampleProjection.updated).not.to.be.true exampleRemote.command 'UpdateExample', id: testExampleId .then -> exampleProjection = exampleRemote.getProjectionInstance projectionId expect(exampleProjection.updated).to.be.true it 'then should publish an event whenever a remote projection is updated', (done) -> testExampleId = null exampleRemote.command 'CreateExample' .then (exampleId) -> testExampleId = exampleId exampleRemote.initializeProjectionInstance 'ExampleProjection', aggregateId: exampleId .then (projectionId) -> exampleProjection = exampleRemote.getProjectionInstance projectionId exampleRemote.subscribe 'projection:ExampleProjection:changed', -> done() exampleRemote.command 'UpdateExample', id: testExampleId it 'then we should be able to remove it', -> exampleRemote.initializeProjectionInstance 'ExampleProjection', aggregateId: '123' .then (projectionId) -> sandbox.spy exampleRemote, 'unsubscribeFromDomainEvent' exampleRemote.destroyProjectionInstance projectionId expect(exampleRemote.getProjectionInstance projectionId).to.be.undefined expect(exampleRemote.unsubscribeFromDomainEvent).to.have.been.called describe 'when we add a remote projection and already have domain events for it', -> exampleRemote = null beforeEach -> exampleRemote = eventric.remote 'Example' class ExampleProjection constructor: -> @exampleCount = 0 handleExampleCreated: -> @exampleCount++ exampleRemote.addProjection 'ExampleProjection', ExampleProjection it 'then it should apply the already existing domain events immediately to the projection', -> exampleContext.command 'CreateExample' .then (id) -> exampleRemote.initializeProjectionInstance 'ExampleProjection' .then (projectionId) -> projection = exampleRemote.getProjectionInstance projectionId expect(projection.exampleCount).to.equal 1 describe 'when we add a remote projection for a specific aggregate id and have domain events for it', -> exampleRemote = null beforeEach -> exampleRemote = eventric.remote 'Example' class ExampleProjection constructor: -> @updated = false initialize: (params, done) -> @$subscribeHandlersWithAggregateId params.aggregateId done() handleExampleUpdated: -> @updated = true exampleRemote.addProjection 'ExampleProjection', ExampleProjection it 'then it should apply the already existing domain events immediately to the projection', -> exampleContext.command 'CreateExample' .then (exampleId) -> exampleContext.command 'UpdateExample', id: exampleId .then (exampleId) -> exampleRemote.initializeProjectionInstance 'ExampleProjection', aggregateId: exampleId .then (projectionId) -> projection = exampleRemote.getProjectionInstance projectionId expect(projection.updated).to.be.true it 'then it should only apply the already existing domain events for the specific aggregate', -> firstExampleId = null exampleContext.command 'CreateExample' .then (_firstExampleId) -> firstExampleId = _firstExampleId exampleContext.command 'CreateExample' .then (secondExampleId) -> exampleContext.command 'UpdateExample', id: secondExampleId .then -> exampleRemote.initializeProjectionInstance 'ExampleProjection', aggregateId: firstExampleId .then (projectionId) -> projection = exampleRemote.getProjectionInstance projectionId expect(projection.updated).to.be.false describe 'when we add a remote projection and already have multiple domain events for it', -> exampleRemote = null beforeEach -> exampleRemote = eventric.remote 'Example' class ExampleProjection constructor: -> @events = [] handleExampleCreated: (domainEvent) -> @events.push domainEvent.name handleExampleUpdated: (domainEvent) -> @events.push domainEvent.name exampleRemote.addProjection 'ExampleProjection', ExampleProjection it 'then it should apply the already existing domain events in the correct order', -> exampleContext.command 'CreateExample' .then (id) -> exampleContext.command 'UpdateExample', id: id .then (id) -> exampleRemote.initializeProjectionInstance 'ExampleProjection' .then (projectionId) -> projection = exampleRemote.getProjectionInstance projectionId expect(projection.events).to.deep.equal ['ExampleCreated', 'ExampleUpdated']