Skip to content

Commit

Permalink
Merge pull request #370 from RailsEventStore/publish-matcher
Browse files Browse the repository at this point in the history
Publish rspec matcher
  • Loading branch information
mostlyobvious authored Jul 13, 2018
2 parents d8f4511 + d74ed34 commit 1fc1c16
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 1 deletion.
4 changes: 3 additions & 1 deletion rails_event_store-rspec/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ IGNORE = RailsEventStore::RSpec::Matchers\#differ \
RailsEventStore::RSpec::Matchers\#formatter \
RailsEventStore::RSpec::Matchers\#have_published \
RailsEventStore::RSpec::Matchers\#have_applied \
RailsEventStore::RSpec::Matchers\#be_an_event
RailsEventStore::RSpec::Matchers\#publish \
RailsEventStore::RSpec::Matchers\#be_an_event \
RailsEventStore::RSpec::Publish\#last_event
SUBJECT ?= RailsEventStore::RSpec*

install: ## Install gem dependencies
Expand Down
1 change: 1 addition & 0 deletions rails_event_store-rspec/lib/rails_event_store/rspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module RSpec
require "rails_event_store/rspec/be_event"
require "rails_event_store/rspec/have_published"
require "rails_event_store/rspec/have_applied"
require "rails_event_store/rspec/publish"
require "rails_event_store/rspec/matchers"

::RSpec.configure do |config|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ def have_applied(*expected)
HaveApplied.new(*expected, differ: differ, phraser: phraser)
end

def publish(*expected)
Publish.new(*expected)
end

private

def formatter
Expand Down
90 changes: 90 additions & 0 deletions rails_event_store-rspec/lib/rails_event_store/rspec/publish.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
require 'rspec/matchers/built_in/base_matcher'

module RailsEventStore
module RSpec
class Publish
def in(event_store)
@event_store = event_store
self
end

def in_stream(stream)
@stream = stream
self
end

def matches?(event_proc)
raise_event_store_not_set unless @event_store
spec = @event_store.read
spec = spec.stream(@stream) if @stream
last_event_before_block = last_event(spec)
event_proc.call
spec = spec.from(last_event_before_block.event_id) if last_event_before_block
@published_events = spec.each.to_a
if match_events?
::RSpec::Matchers::BuiltIn::Include.new(*@expected).matches?(@published_events)
else
!@published_events.empty?
end
end

def failure_message
if match_events?
<<-EOS
expected block to have published:
#{@expected}
#{"in stream #{@stream} " if @stream}but published:
#{@published_events}
EOS
else
"expected block to have published any events"
end
end

def failure_message_when_negated
if match_events?
<<-EOS
expected block not to have published:
#{@expected}
#{"in stream #{@stream} " if @stream}but published:
#{@published_events}
EOS
else
"expected block not to have published any events"
end
end

def description
"publish events"
end

def supports_block_expectations?
true
end

private

def initialize(*expected)
@expected = expected
end

def match_events?
!@expected.empty?
end

def last_event(spec)
spec.backward.limit(1).each.first
end

def raise_event_store_not_set
raise SyntaxError, "You have to set the event store instance with `in`, e.g. `expect { ... }.to publish(an_event(MyEvent)).in(event_store)`"
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ module RSpec
expect(event_store).to matchers.have_published(matchers.an_event(FooEvent), matchers.an_event(BarEvent))
end

specify do
event_store = RailsEventStore::Client.new(repository: RailsEventStore::InMemoryRepository.new)
event_store.publish_event(FooEvent.new)
expect {
event_store.publish_event(BarEvent.new)
}.to publish(matchers.an_event(BarEvent)).in(event_store)
end

specify { expect(matchers.have_applied(matchers.an_event(FooEvent))).to be_an(HaveApplied) }

specify do
Expand All @@ -60,6 +68,10 @@ module RSpec
aggregate_root.bar
expect(aggregate_root).to matchers.have_applied(matchers.an_event(FooEvent), matchers.an_event(BarEvent))
end

specify do
expect(matchers.publish).to be_a(Publish)
end
end

module Matchers
Expand Down
185 changes: 185 additions & 0 deletions rails_event_store-rspec/spec/rails_event_store/rspec/publish_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
require "spec_helper"

module RailsEventStore
module RSpec
::RSpec.describe Publish do
let(:matchers) { Object.new.tap { |o| o.extend(Matchers) } }
let(:event_store) do
RailsEventStore::Client.new(
repository: RailsEventStore::InMemoryRepository.new,
mapper: RubyEventStore::Mappers::NullMapper.new
)
end

def matcher(*expected)
Publish.new(*expected)
end

specify do
expect {
expect {
true
}.to matcher
}.to raise_error(SyntaxError, "You have to set the event store instance with `in`, e.g. `expect { ... }.to publish(an_event(MyEvent)).in(event_store)`")
end

specify do
expect {
true
}.not_to matcher.in(event_store)
end

specify do
expect {
event_store.publish_event(FooEvent.new)
}.to matcher.in(event_store)
end

specify do
expect {
event_store.publish_event(FooEvent.new, stream_name: 'Foo$1')
}.to matcher.in(event_store).in_stream('Foo$1')
end

specify do
expect {
event_store.publish_event(FooEvent.new, stream_name: 'Foo$1')
}.not_to matcher.in(event_store).in_stream('Bar$1')
end

specify do
expect {
event_store.publish_event(FooEvent.new)
}.not_to matcher(matchers.an_event(BarEvent)).in(event_store)
end

specify do
expect {
event_store.publish_event(FooEvent.new)
}.to matcher(matchers.an_event(FooEvent)).in(event_store)
end

specify do
expect {
event_store.publish_event(FooEvent.new, stream_name: "Foo$1")
}.to matcher(matchers.an_event(FooEvent)).in(event_store).in_stream("Foo$1")
end

specify do
expect {
event_store.publish_event(FooEvent.new)
}.not_to matcher(matchers.an_event(FooEvent)).in(event_store).in_stream("Foo$1")
end

specify do
foo_event = FooEvent.new
bar_event = BarEvent.new
expect {
event_store.publish_event(foo_event, stream_name: "Foo$1")
event_store.publish_event(bar_event, stream_name: "Bar$1")
}.to matcher(matchers.an_event(FooEvent), matchers.an_event(BarEvent)).in(event_store)
end

specify do
foo_event = FooEvent.new
bar_event = BarEvent.new

event_store.publish_event(foo_event)
expect {
event_store.publish_event(bar_event)
}.not_to matcher(matchers.an_event(FooEvent)).in(event_store)
end

specify do
expect {
true
}.not_to matcher.in(event_store)
end

specify do
_matcher = matcher.in(event_store)
_matcher.matches?(Proc.new { })

expect(_matcher.failure_message_when_negated.to_s).to eq(<<~EOS.strip)
expected block not to have published any events
EOS
end

specify do
_matcher = matcher.in(event_store)
_matcher.matches?(Proc.new { })

expect(_matcher.failure_message.to_s).to eq(<<~EOS.strip)
expected block to have published any events
EOS
end

specify do
_matcher = matcher(actual = matchers.an_event(FooEvent)).in(event_store)
_matcher.matches?(Proc.new { })

expect(_matcher.failure_message.to_s).to eq(<<~EOS)
expected block to have published:
#{[actual].inspect}
but published:
[]
EOS
end

specify do
_matcher = matcher(actual = matchers.an_event(FooEvent)).in_stream('foo').in(event_store)
_matcher.matches?(Proc.new { })

expect(_matcher.failure_message.to_s).to eq(<<~EOS)
expected block to have published:
#{[actual].inspect}
in stream foo but published:
[]
EOS
end

specify do
foo_event = FooEvent.new
_matcher = matcher(actual = matchers.an_event(FooEvent)).in(event_store)
_matcher.matches?(Proc.new { event_store.publish_event(foo_event) })

expect(_matcher.failure_message_when_negated.to_s).to eq(<<~EOS)
expected block not to have published:
#{[actual].inspect}
but published:
#{[foo_event].inspect}
EOS
end

specify do
foo_event = FooEvent.new
_matcher = matcher(actual = matchers.an_event(FooEvent)).in_stream('foo').in(event_store)
_matcher.matches?(Proc.new { event_store.publish_event(foo_event, stream_name: 'foo') })

expect(_matcher.failure_message_when_negated.to_s).to eq(<<~EOS)
expected block not to have published:
#{[actual].inspect}
in stream foo but published:
#{[foo_event].inspect}
EOS
end

specify do
_matcher = matcher
expect(_matcher.description).to eq("publish events")
end
end
end
end

0 comments on commit 1fc1c16

Please sign in to comment.