rails_event_store-rspec 1.3.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rails_event_store/rspec.rb +9 -17
- metadata +17 -23
- data/.gitignore +0 -12
- data/Gemfile +0 -13
- data/Makefile +0 -18
- data/README.md +0 -192
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/lib/rails_event_store/rspec/apply.rb +0 -84
- data/lib/rails_event_store/rspec/be_event.rb +0 -190
- data/lib/rails_event_store/rspec/have_applied.rb +0 -66
- data/lib/rails_event_store/rspec/have_published.rb +0 -78
- data/lib/rails_event_store/rspec/matchers.rb +0 -68
- data/lib/rails_event_store/rspec/publish.rb +0 -86
- data/lib/rails_event_store/rspec/version.rb +0 -7
- data/rails_event_store-rspec.gemspec +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8345bd2f3ee4640d856c1d9c485816b812308ef8793f504135fe89a3c849e6e
|
4
|
+
data.tar.gz: 7be6f9ff566c5f3f9eed075c329bce862365edac9d78848fd854c324de71eed5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 343a9c188f29c1b478315fa12b18bcab018742c06b83f844e0f6ce1efc2a1214dda493fda9e0f551a95fdcc08f2321eee00637f12d0ab23bea4c124981e21440
|
7
|
+
data.tar.gz: 95525a009882fb17e0df3fb53dc43d1c924823845f950f1d2145321e9c6044bb56b29e810dcce5f9ebb8308bf2f088cbb905e39e7c9a6608cb4a64c254f8c758
|
@@ -1,21 +1,13 @@
|
|
1
|
-
|
1
|
+
require 'ruby_event_store/rspec'
|
2
2
|
|
3
|
-
|
3
|
+
warn <<~EOW
|
4
|
+
The 'rails_event_store-rspec' gem has been renamed.
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
NotSupported = Class.new(StandardError)
|
8
|
-
end
|
9
|
-
end
|
6
|
+
Please change your Gemfile or gemspec
|
7
|
+
to reflect its new name:
|
10
8
|
|
11
|
-
|
12
|
-
require "rails_event_store/rspec/be_event"
|
13
|
-
require "rails_event_store/rspec/have_published"
|
14
|
-
require "rails_event_store/rspec/have_applied"
|
15
|
-
require "rails_event_store/rspec/publish"
|
16
|
-
require "rails_event_store/rspec/apply"
|
17
|
-
require "rails_event_store/rspec/matchers"
|
9
|
+
'ruby_event_store-rspec'
|
18
10
|
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
EOW
|
12
|
+
|
13
|
+
RailsEventStore::RSpec = RubyEventStore::RSpec
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_event_store-rspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arkency
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-12-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -25,19 +25,19 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: ruby_event_store-rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 2.0.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 2.0.0
|
41
41
|
description:
|
42
42
|
email:
|
43
43
|
- dev@arkency.com
|
@@ -45,21 +45,7 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
-
- ".gitignore"
|
49
|
-
- Gemfile
|
50
|
-
- Makefile
|
51
|
-
- README.md
|
52
|
-
- bin/console
|
53
|
-
- bin/setup
|
54
48
|
- lib/rails_event_store/rspec.rb
|
55
|
-
- lib/rails_event_store/rspec/apply.rb
|
56
|
-
- lib/rails_event_store/rspec/be_event.rb
|
57
|
-
- lib/rails_event_store/rspec/have_applied.rb
|
58
|
-
- lib/rails_event_store/rspec/have_published.rb
|
59
|
-
- lib/rails_event_store/rspec/matchers.rb
|
60
|
-
- lib/rails_event_store/rspec/publish.rb
|
61
|
-
- lib/rails_event_store/rspec/version.rb
|
62
|
-
- rails_event_store-rspec.gemspec
|
63
49
|
homepage: https://railseventstore.org
|
64
50
|
licenses:
|
65
51
|
- MIT
|
@@ -68,7 +54,14 @@ metadata:
|
|
68
54
|
changelog_uri: https://github.com/RailsEventStore/rails_event_store/releases
|
69
55
|
source_code_uri: https://github.com/RailsEventStore/rails_event_store
|
70
56
|
bug_tracker_uri: https://github.com/RailsEventStore/rails_event_store/issues
|
71
|
-
post_install_message:
|
57
|
+
post_install_message: |+
|
58
|
+
The 'rails_event_store-rspec' gem has been renamed.
|
59
|
+
|
60
|
+
Please change your Gemfile or gemspec
|
61
|
+
to reflect its new name:
|
62
|
+
|
63
|
+
'ruby_event_store-rspec'
|
64
|
+
|
72
65
|
rdoc_options: []
|
73
66
|
require_paths:
|
74
67
|
- lib
|
@@ -88,3 +81,4 @@ signing_key:
|
|
88
81
|
specification_version: 4
|
89
82
|
summary: RSpec matchers for RailsEventStore
|
90
83
|
test_files: []
|
84
|
+
...
|
data/.gitignore
DELETED
data/Gemfile
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
3
|
-
gemspec
|
4
|
-
|
5
|
-
eval_gemfile File.expand_path('../support/bundler/Gemfile.shared', __dir__)
|
6
|
-
|
7
|
-
gem 'rails_event_store', path: '../rails_event_store'
|
8
|
-
gem 'rails_event_store_active_record', path: '../rails_event_store_active_record'
|
9
|
-
gem 'ruby_event_store', path: '../ruby_event_store'
|
10
|
-
gem 'ruby_event_store-browser', path: '../ruby_event_store-browser'
|
11
|
-
gem 'aggregate_root', path: '../aggregate_root'
|
12
|
-
gem 'bounded_context', path: '../bounded_context'
|
13
|
-
gem 'rails', ENV['RAILS_VERSION']
|
data/Makefile
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
GEM_VERSION = $(shell cat ../RES_VERSION)
|
2
|
-
GEM_NAME = rails_event_store-rspec
|
3
|
-
REQUIRE = rails_event_store/rspec
|
4
|
-
IGNORE = RailsEventStore::RSpec::Matchers\#differ \
|
5
|
-
RailsEventStore::RSpec::Matchers\#formatter \
|
6
|
-
RailsEventStore::RSpec::Matchers\#have_published \
|
7
|
-
RailsEventStore::RSpec::Matchers\#have_applied \
|
8
|
-
RailsEventStore::RSpec::Matchers\#publish \
|
9
|
-
RailsEventStore::RSpec::Matchers\#be_an_event \
|
10
|
-
RailsEventStore::RSpec::Publish\#last_event
|
11
|
-
SUBJECT ?= RailsEventStore::RSpec*
|
12
|
-
DATABASE_URL ?= sqlite3::memory:
|
13
|
-
|
14
|
-
include ../support/make/install.mk
|
15
|
-
include ../support/make/test.mk
|
16
|
-
include ../support/make/mutant.mk
|
17
|
-
include ../support/make/gem.mk
|
18
|
-
include ../support/make/help.mk
|
data/README.md
DELETED
@@ -1,192 +0,0 @@
|
|
1
|
-
# RailsEventStore::RSpec
|
2
|
-
|
3
|
-
## Installation
|
4
|
-
|
5
|
-
Add this line to your application's Gemfile:
|
6
|
-
|
7
|
-
```ruby
|
8
|
-
group :test do
|
9
|
-
gem 'rails_event_store-rspec'
|
10
|
-
end
|
11
|
-
```
|
12
|
-
|
13
|
-
## Usage
|
14
|
-
|
15
|
-
### be_event
|
16
|
-
|
17
|
-
The `be_event` matcher enables you to make expectations on a domain event. It exposes fluent interface.
|
18
|
-
|
19
|
-
```ruby
|
20
|
-
OrderPlaced = Class.new(RailsEventStore::Event)
|
21
|
-
domain_event = OrderPlaced.new(
|
22
|
-
data: {
|
23
|
-
order_id: 42,
|
24
|
-
net_value: BigDecimal.new("1999.0")
|
25
|
-
},
|
26
|
-
metadata: {
|
27
|
-
remote_ip: '1.2.3.4'
|
28
|
-
}
|
29
|
-
)
|
30
|
-
|
31
|
-
expect(domain_event)
|
32
|
-
.to(be_an_event(OrderPlaced)
|
33
|
-
.with_data(order_id: 42, net_value: BigDecimal.new("1999.0"))
|
34
|
-
.with_metadata(remote_ip: '1.2.3.4'))
|
35
|
-
```
|
36
|
-
|
37
|
-
By default the behaviour of `with_data` and `with_metadata` is not strict, that is the expectation is met when all specified values for keys match. Additional data or metadata that is not specified to be expected does not change the outcome.
|
38
|
-
|
39
|
-
```ruby
|
40
|
-
domain_event = OrderPlaced.new(
|
41
|
-
data: {
|
42
|
-
order_id: 42,
|
43
|
-
net_value: BigDecimal.new("1999.0")
|
44
|
-
}
|
45
|
-
)
|
46
|
-
|
47
|
-
# this would pass even though data contains also net_value
|
48
|
-
expect(domain_event).to be_an_event(OrderPlaced).with_data(order_id: 42)
|
49
|
-
```
|
50
|
-
|
51
|
-
This matcher is both [composable](http://rspec.info/blog/2014/01/new-in-rspec-3-composable-matchers/) and accepting [built-in matchers](https://relishapp.com/rspec/rspec-expectations/v/3-6/docs/built-in-matchers) as a part of an expectation.
|
52
|
-
|
53
|
-
```ruby
|
54
|
-
expect(domain_event).to be_an_event(OrderPlaced).with_data(order_id: kind_of(Integer))
|
55
|
-
expect([domain_event]).to include(an_event(OrderPlaced))
|
56
|
-
```
|
57
|
-
|
58
|
-
If you depend on matching the exact data or metadata, there's a `strict` modifier.
|
59
|
-
|
60
|
-
```ruby
|
61
|
-
domain_event = OrderPlaced.new(
|
62
|
-
data: {
|
63
|
-
order_id: 42,
|
64
|
-
net_value: BigDecimal.new("1999.0")
|
65
|
-
}
|
66
|
-
)
|
67
|
-
|
68
|
-
# this would fail as data contains unexpected net_value
|
69
|
-
expect(domain_event).to be_an_event(OrderPlaced).with_data(order_id: 42).strict
|
70
|
-
```
|
71
|
-
|
72
|
-
Mind that `strict` makes both `with_data` and `with_metadata` behave in a stricter way. If you need to mix both, i.e. strict data but non-strict metadata then consider composing matchers.
|
73
|
-
|
74
|
-
```ruby
|
75
|
-
expect(domain_event)
|
76
|
-
.to(be_event(OrderPlaced).with_data(order_id: 42, net_value: BigDecimal.new("1999.0")).strict
|
77
|
-
.and(an_event(OrderPlaced).with_metadata(timestamp: kind_of(Time)))
|
78
|
-
```
|
79
|
-
|
80
|
-
You may have noticed the same matcher being referenced as `be_event`, `be_an_event` and `an_event`. There's also just `event`. Use whichever reads better grammatically.
|
81
|
-
|
82
|
-
### have_published
|
83
|
-
|
84
|
-
Use this matcher to target `event_store` and reading from streams specifically.
|
85
|
-
In a simplest form it would read all streams backward up to a page limit (100 events) and check whether the expectation holds true. Its behaviour can be best compared to the `include` matcher — it is satisfied by at least one element present in the collection. You're encouraged to compose it with `be_event`.
|
86
|
-
|
87
|
-
```ruby
|
88
|
-
event_store = RailsEventStore::Client.new
|
89
|
-
event_store.publish(OrderPlaced.new(data: { order_id: 42 }))
|
90
|
-
|
91
|
-
expect(event_store).to have_published(an_event(OrderPlaced))
|
92
|
-
```
|
93
|
-
|
94
|
-
Expectation can be narrowed to the specific stream.
|
95
|
-
|
96
|
-
```ruby
|
97
|
-
event_store = RailsEventStore::Client.new
|
98
|
-
event_store.publish(OrderPlaced.new(data: { order_id: 42 }), stream_name: "Order$42")
|
99
|
-
|
100
|
-
expect(event_store).to have_published(an_event(OrderPlaced)).in_stream("Order$42")
|
101
|
-
```
|
102
|
-
|
103
|
-
It is sometimes important to ensure no additional events have been published. Luckliy there's a modifier to cover that usecase.
|
104
|
-
|
105
|
-
```ruby
|
106
|
-
expect(event_store).not_to have_published(an_event(OrderPlaced)).once
|
107
|
-
expect(event_store).to have_published(an_event(OrderPlaced)).exactly(2).times
|
108
|
-
```
|
109
|
-
|
110
|
-
Finally you can make expectation on several events at once.
|
111
|
-
|
112
|
-
```ruby
|
113
|
-
expect(event_store).to have_published(
|
114
|
-
an_event(OrderPlaced),
|
115
|
-
an_event(OrderExpired).with_data(expired_at: be_between(Date.yesterday, Date.tomorrow))
|
116
|
-
)
|
117
|
-
```
|
118
|
-
|
119
|
-
If there's a usecase not covered by examples above or you need a different set of events to make expectations on you can always resort to a more verbose approach and skip `have_published`.
|
120
|
-
|
121
|
-
```ruby
|
122
|
-
expect(event_store.read_events_forward("OrderAuditLog$42", count: 2)).to eq([
|
123
|
-
an_event(OrderPlaced),
|
124
|
-
an_event(OrderExpired)
|
125
|
-
])
|
126
|
-
```
|
127
|
-
|
128
|
-
### have_applied
|
129
|
-
|
130
|
-
This matcher is intended to be used on [aggregate root](https://github.com/RailsEventStore/rails_event_store/tree/master/aggregate_root#usage). Behaviour is almost identical to `have_published` counterpart, except the concept of stream. Expecations are made against internal unpublished events collection.
|
131
|
-
|
132
|
-
```ruby
|
133
|
-
class Order
|
134
|
-
include AggregateRoot
|
135
|
-
HasBeenAlreadySubmitted = Class.new(StandardError)
|
136
|
-
HasExpired = Class.new(StandardError)
|
137
|
-
|
138
|
-
def initialize
|
139
|
-
self.state = :new
|
140
|
-
# any other code here
|
141
|
-
end
|
142
|
-
|
143
|
-
def submit
|
144
|
-
raise HasBeenAlreadySubmitted if state == :submitted
|
145
|
-
raise HasExpired if state == :expired
|
146
|
-
apply OrderSubmitted.new(data: {delivery_date: Time.now + 24.hours})
|
147
|
-
end
|
148
|
-
|
149
|
-
def expire
|
150
|
-
apply OrderExpired.new
|
151
|
-
end
|
152
|
-
|
153
|
-
private
|
154
|
-
attr_accessor :state
|
155
|
-
|
156
|
-
def apply_order_submitted(event)
|
157
|
-
self.state = :submitted
|
158
|
-
end
|
159
|
-
|
160
|
-
def apply_order_expired(event)
|
161
|
-
self.state = :expired
|
162
|
-
end
|
163
|
-
end
|
164
|
-
```
|
165
|
-
|
166
|
-
```ruby
|
167
|
-
aggregate_root = Order.new
|
168
|
-
aggregate_root.submit
|
169
|
-
|
170
|
-
expect(aggregate_root).to have_applied(event(OrderSubmitted)).once
|
171
|
-
```
|
172
|
-
## Code status
|
173
|
-
|
174
|
-
[![Build Status](https://travis-ci.org/RailsEventStore/rails_event_store-rspec.svg?branch=master)](https://travis-ci.org/RailsEventStore/rails_event_store-rspec)
|
175
|
-
[![Gem Version](https://badge.fury.io/rb/rails_event_store-rspec.svg)](https://badge.fury.io/rb/rails_event_store-rspec)
|
176
|
-
|
177
|
-
We're aiming for 100% mutation coverage in this project. This is why:
|
178
|
-
|
179
|
-
* [Why I want to introduce mutation testing to the rails_event_store gem](https://blog.arkency.com/2015/04/why-i-want-to-introduce-mutation-testing-to-the-rails-event-store-gem/)
|
180
|
-
* [Mutation testing and continuous integration](https://blog.arkency.com/2015/05/mutation-testing-and-continuous-integration/)
|
181
|
-
|
182
|
-
Whenever you fix a bug or add a new feature, we require that the coverage doesn't go down.
|
183
|
-
|
184
|
-
## Development
|
185
|
-
|
186
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
187
|
-
|
188
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
189
|
-
|
190
|
-
## Contributing
|
191
|
-
|
192
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/RailsEventStore/rails_event_store-rspec.
|
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "rails_event_store/rspec"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start(__FILE__)
|
data/bin/setup
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RailsEventStore
|
4
|
-
module RSpec
|
5
|
-
class Apply
|
6
|
-
def in(aggregate)
|
7
|
-
@aggregate = aggregate
|
8
|
-
self
|
9
|
-
end
|
10
|
-
|
11
|
-
def strict
|
12
|
-
@matcher = ::RSpec::Matchers::BuiltIn::Match.new(@expected)
|
13
|
-
self
|
14
|
-
end
|
15
|
-
|
16
|
-
def matches?(event_proc)
|
17
|
-
raise_aggregate_not_set unless @aggregate
|
18
|
-
before = @aggregate.unpublished_events.to_a
|
19
|
-
event_proc.call
|
20
|
-
@applied_events = @aggregate.unpublished_events.to_a - before
|
21
|
-
if match_events?
|
22
|
-
@matcher.matches?(@applied_events)
|
23
|
-
else
|
24
|
-
!@applied_events.empty?
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def failure_message
|
29
|
-
if match_events?
|
30
|
-
<<-EOS
|
31
|
-
expected block to have applied:
|
32
|
-
|
33
|
-
#{@expected}
|
34
|
-
|
35
|
-
but applied:
|
36
|
-
|
37
|
-
#{@applied_events}
|
38
|
-
EOS
|
39
|
-
else
|
40
|
-
"expected block to have applied any events"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def failure_message_when_negated
|
45
|
-
if match_events?
|
46
|
-
<<-EOS
|
47
|
-
expected block not to have applied:
|
48
|
-
|
49
|
-
#{@expected}
|
50
|
-
|
51
|
-
but applied:
|
52
|
-
|
53
|
-
#{@applied_events}
|
54
|
-
EOS
|
55
|
-
else
|
56
|
-
"expected block not to have applied any events"
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def description
|
61
|
-
"apply events"
|
62
|
-
end
|
63
|
-
|
64
|
-
def supports_block_expectations?
|
65
|
-
true
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
def initialize(*expected)
|
71
|
-
@expected = expected
|
72
|
-
@matcher = ::RSpec::Matchers::BuiltIn::Include.new(*expected)
|
73
|
-
end
|
74
|
-
|
75
|
-
def match_events?
|
76
|
-
!@expected.empty?
|
77
|
-
end
|
78
|
-
|
79
|
-
def raise_aggregate_not_set
|
80
|
-
raise SyntaxError, "You have to set the aggregate instance with `in`, e.g. `expect { ... }.to apply(an_event(MyEvent)).in(aggregate)`"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
@@ -1,190 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RailsEventStore
|
4
|
-
module RSpec
|
5
|
-
class BeEvent
|
6
|
-
class KindMatcher
|
7
|
-
def initialize(expected)
|
8
|
-
@expected = expected
|
9
|
-
end
|
10
|
-
|
11
|
-
def matches?(actual)
|
12
|
-
@expected === actual
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class DataMatcher
|
17
|
-
def initialize(expected, strict:)
|
18
|
-
@strict = strict
|
19
|
-
@expected = expected
|
20
|
-
end
|
21
|
-
|
22
|
-
def matches?(actual)
|
23
|
-
return true unless @expected
|
24
|
-
matcher = @strict ? ::RSpec::Matchers::BuiltIn::Match : ::RSpec::Matchers::BuiltIn::Include
|
25
|
-
matcher.new(@expected).matches?(actual)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
class FailureMessage
|
30
|
-
class ExpectedLine
|
31
|
-
def initialize(expected_klass, expected_metadata, expected_data)
|
32
|
-
@expected_klass = expected_klass
|
33
|
-
@expected_metadata = expected_metadata
|
34
|
-
@expected_data = expected_data
|
35
|
-
end
|
36
|
-
|
37
|
-
def to_s
|
38
|
-
["\nexpected: ", @expected_klass, with, metadata, data]
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def with
|
44
|
-
" with" if [@expected_data, @expected_metadata].any?
|
45
|
-
end
|
46
|
-
|
47
|
-
def data
|
48
|
-
[" data: ", @expected_data] if @expected_data
|
49
|
-
end
|
50
|
-
|
51
|
-
def metadata
|
52
|
-
[" metadata: ", @expected_metadata] if @expected_metadata
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
class ActualLine
|
57
|
-
def initialize(actual_klass, actual_metadata, actual_data, expected_metadata, expected_data)
|
58
|
-
@actual_klass = actual_klass
|
59
|
-
@actual_metadata = actual_metadata
|
60
|
-
@actual_data = actual_data
|
61
|
-
@expected_metadata = expected_metadata
|
62
|
-
@expected_data = expected_data
|
63
|
-
end
|
64
|
-
|
65
|
-
def to_s
|
66
|
-
["\n got: ", @actual_klass, with, metadata, data, "\n"]
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def with
|
72
|
-
" with" if [@expected_data, @expected_metadata].any?
|
73
|
-
end
|
74
|
-
|
75
|
-
def data
|
76
|
-
[" data: ", @actual_data] if @expected_data
|
77
|
-
end
|
78
|
-
|
79
|
-
def metadata
|
80
|
-
[" metadata: ", @actual_metadata] if @expected_metadata
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
class Diff
|
85
|
-
def initialize(actual, expected, label, differ:)
|
86
|
-
@actual = actual
|
87
|
-
@expected = expected
|
88
|
-
@label = label
|
89
|
-
@differ = differ
|
90
|
-
end
|
91
|
-
|
92
|
-
def to_s
|
93
|
-
@expected && ["\n#{@label} diff:", @differ.diff_as_string(@actual.to_s, @expected.to_s)]
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def initialize(expected_klass, actual_klass, expected_data, actual_data, expected_metadata, actual_metadata, differ:)
|
98
|
-
@expected_klass = expected_klass
|
99
|
-
@actual_klass = actual_klass
|
100
|
-
@expected_data = expected_data
|
101
|
-
@actual_data = actual_data
|
102
|
-
@expected_metadata = expected_metadata
|
103
|
-
@actual_metadata = actual_metadata
|
104
|
-
@differ = differ
|
105
|
-
end
|
106
|
-
|
107
|
-
def to_s
|
108
|
-
[
|
109
|
-
ExpectedLine.new(@expected_klass, @expected_metadata, @expected_data),
|
110
|
-
ActualLine.new(@actual_klass, @actual_metadata.to_h, @actual_data, @expected_metadata, @expected_data),
|
111
|
-
Diff.new(@actual_metadata.to_h, @expected_metadata, "Metadata", differ: @differ),
|
112
|
-
Diff.new(@actual_data, @expected_data, "Data", differ: @differ)
|
113
|
-
].map(&:to_s).join
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
include ::RSpec::Matchers::Composable
|
118
|
-
|
119
|
-
def initialize(expected, differ:, formatter:)
|
120
|
-
@expected = expected
|
121
|
-
@differ = differ
|
122
|
-
@formatter = formatter
|
123
|
-
end
|
124
|
-
|
125
|
-
def matches?(actual)
|
126
|
-
@actual = actual
|
127
|
-
matches_kind && matches_data && matches_metadata
|
128
|
-
end
|
129
|
-
|
130
|
-
def with_data(expected_data)
|
131
|
-
@expected_data = expected_data
|
132
|
-
self
|
133
|
-
end
|
134
|
-
|
135
|
-
def with_metadata(expected_metadata)
|
136
|
-
@expected_metadata = expected_metadata
|
137
|
-
self
|
138
|
-
end
|
139
|
-
|
140
|
-
def failure_message
|
141
|
-
FailureMessage.new(expected, actual.class, expected_data, actual.try(:data), expected_metadata, actual.try(:metadata), differ: differ).to_s
|
142
|
-
end
|
143
|
-
|
144
|
-
def failure_message_when_negated
|
145
|
-
%Q{
|
146
|
-
expected: not a kind of #{expected}
|
147
|
-
got: #{actual.class}
|
148
|
-
}
|
149
|
-
end
|
150
|
-
|
151
|
-
def strict
|
152
|
-
@strict = true
|
153
|
-
self
|
154
|
-
end
|
155
|
-
|
156
|
-
def description
|
157
|
-
"be an event #{formatter.(expected)}#{data_and_metadata_expectations_description}"
|
158
|
-
end
|
159
|
-
|
160
|
-
def data_and_metadata_expectations_description
|
161
|
-
predicate = strict? ? "matching" : "including"
|
162
|
-
expectation_list = []
|
163
|
-
expectation_list << "with data #{predicate} #{formatter.(expected_data)}" if expected_data
|
164
|
-
expectation_list << "with metadata #{predicate} #{formatter.(expected_metadata)}" if expected_metadata
|
165
|
-
" (#{expectation_list.join(" and ")})" if expectation_list.any?
|
166
|
-
end
|
167
|
-
|
168
|
-
private
|
169
|
-
|
170
|
-
def matches_kind
|
171
|
-
KindMatcher.new(expected).matches?(actual)
|
172
|
-
end
|
173
|
-
|
174
|
-
def matches_data
|
175
|
-
DataMatcher.new(expected_data, strict: strict?).matches?(actual.data)
|
176
|
-
end
|
177
|
-
|
178
|
-
def matches_metadata
|
179
|
-
DataMatcher.new(expected_metadata, strict: strict?).matches?(actual.metadata.to_h)
|
180
|
-
end
|
181
|
-
|
182
|
-
attr_reader :expected_metadata, :expected_data, :actual, :expected, :differ, :formatter
|
183
|
-
|
184
|
-
def strict?
|
185
|
-
@strict
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
@@ -1,66 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RailsEventStore
|
4
|
-
module RSpec
|
5
|
-
class HaveApplied
|
6
|
-
def initialize(mandatory_expected, *optional_expected, differ:, phraser:)
|
7
|
-
@expected = [mandatory_expected, *optional_expected]
|
8
|
-
@matcher = ::RSpec::Matchers::BuiltIn::Include.new(*expected)
|
9
|
-
@differ = differ
|
10
|
-
@phraser = phraser
|
11
|
-
end
|
12
|
-
|
13
|
-
def matches?(aggregate_root)
|
14
|
-
@events = aggregate_root.unpublished_events.to_a
|
15
|
-
matcher.matches?(events) && matches_count?
|
16
|
-
end
|
17
|
-
|
18
|
-
def exactly(count)
|
19
|
-
@count = count
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
def times
|
24
|
-
self
|
25
|
-
end
|
26
|
-
alias :time :times
|
27
|
-
|
28
|
-
def once
|
29
|
-
exactly(1)
|
30
|
-
end
|
31
|
-
|
32
|
-
def strict
|
33
|
-
@matcher = ::RSpec::Matchers::BuiltIn::Match.new(expected)
|
34
|
-
self
|
35
|
-
end
|
36
|
-
|
37
|
-
def failure_message
|
38
|
-
"expected #{expected} to be applied, diff:" +
|
39
|
-
differ.diff_as_string(expected.to_s, events.to_s)
|
40
|
-
end
|
41
|
-
|
42
|
-
def failure_message_when_negated
|
43
|
-
"expected #{expected} not to be applied, diff:" +
|
44
|
-
differ.diff_as_string(expected.inspect, events.inspect)
|
45
|
-
end
|
46
|
-
|
47
|
-
def description
|
48
|
-
"have applied events that have to (#{phraser.(expected)})"
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def matches_count?
|
54
|
-
return true unless count
|
55
|
-
raise NotSupported if expected.size > 1
|
56
|
-
|
57
|
-
expected.all? do |event_or_matcher|
|
58
|
-
events.select { |e| event_or_matcher === e }.size.equal?(count)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
attr_reader :differ, :phraser, :expected, :events, :count, :matcher
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
@@ -1,78 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RailsEventStore
|
4
|
-
module RSpec
|
5
|
-
class HavePublished
|
6
|
-
def initialize(mandatory_expected, *optional_expected, differ:, phraser:)
|
7
|
-
@expected = [mandatory_expected, *optional_expected]
|
8
|
-
@matcher = ::RSpec::Matchers::BuiltIn::Include.new(*expected)
|
9
|
-
@differ = differ
|
10
|
-
@phraser = phraser
|
11
|
-
end
|
12
|
-
|
13
|
-
def matches?(event_store)
|
14
|
-
@events = event_store.read
|
15
|
-
@events = events.stream(stream_name) if stream_name
|
16
|
-
@events = events.from(start) if start
|
17
|
-
@events = events.each
|
18
|
-
@matcher.matches?(events) && matches_count?
|
19
|
-
end
|
20
|
-
|
21
|
-
def exactly(count)
|
22
|
-
@count = count
|
23
|
-
self
|
24
|
-
end
|
25
|
-
|
26
|
-
def in_stream(stream_name)
|
27
|
-
@stream_name = stream_name
|
28
|
-
self
|
29
|
-
end
|
30
|
-
|
31
|
-
def times
|
32
|
-
self
|
33
|
-
end
|
34
|
-
alias :time :times
|
35
|
-
|
36
|
-
def from(event_id)
|
37
|
-
@start = event_id
|
38
|
-
self
|
39
|
-
end
|
40
|
-
|
41
|
-
def once
|
42
|
-
exactly(1)
|
43
|
-
end
|
44
|
-
|
45
|
-
def failure_message
|
46
|
-
"expected #{expected} to be published, diff:" +
|
47
|
-
differ.diff_as_string(expected.to_s, events.to_a.to_s)
|
48
|
-
end
|
49
|
-
|
50
|
-
def failure_message_when_negated
|
51
|
-
"expected #{expected} not to be published, diff:" +
|
52
|
-
differ.diff_as_string(expected.to_s, events.to_a.to_s)
|
53
|
-
end
|
54
|
-
|
55
|
-
def description
|
56
|
-
"have published events that have to (#{phraser.(expected)})"
|
57
|
-
end
|
58
|
-
|
59
|
-
def strict
|
60
|
-
@matcher = ::RSpec::Matchers::BuiltIn::Match.new(expected)
|
61
|
-
self
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def matches_count?
|
67
|
-
return true unless count
|
68
|
-
raise NotSupported if expected.size > 1
|
69
|
-
|
70
|
-
expected.all? do |event_or_matcher|
|
71
|
-
events.select { |e| event_or_matcher === e }.size.equal?(count)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
attr_reader :differ, :phraser, :stream_name, :expected, :count, :events, :start
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RailsEventStore
|
4
|
-
module RSpec
|
5
|
-
module Matchers
|
6
|
-
class ListPhraser
|
7
|
-
class << self
|
8
|
-
def call(object)
|
9
|
-
items = Array(object).compact.map { |o| format(o) }
|
10
|
-
return "" if items.empty?
|
11
|
-
if items.one?
|
12
|
-
items.join
|
13
|
-
else
|
14
|
-
"#{items[0...-1].join(", ")} and #{items.fetch(-1)}"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def format(object)
|
21
|
-
if object.respond_to?(:description)
|
22
|
-
::RSpec::Support::ObjectFormatter.format(object)
|
23
|
-
else
|
24
|
-
"be a #{object}"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def be_an_event(expected)
|
31
|
-
BeEvent.new(expected, differ: differ, formatter: formatter)
|
32
|
-
end
|
33
|
-
alias :be_event :be_an_event
|
34
|
-
alias :an_event :be_an_event
|
35
|
-
alias :event :be_an_event
|
36
|
-
|
37
|
-
def have_published(*expected)
|
38
|
-
HavePublished.new(*expected, differ: differ, phraser: phraser)
|
39
|
-
end
|
40
|
-
|
41
|
-
def have_applied(*expected)
|
42
|
-
HaveApplied.new(*expected, differ: differ, phraser: phraser)
|
43
|
-
end
|
44
|
-
|
45
|
-
def publish(*expected)
|
46
|
-
Publish.new(*expected)
|
47
|
-
end
|
48
|
-
|
49
|
-
def apply(*expected)
|
50
|
-
Apply.new(*expected)
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
|
-
|
55
|
-
def formatter
|
56
|
-
::RSpec::Support::ObjectFormatter.public_method(:format)
|
57
|
-
end
|
58
|
-
|
59
|
-
def differ
|
60
|
-
::RSpec::Support::Differ.new(color: ::RSpec::Matchers.configuration.color?)
|
61
|
-
end
|
62
|
-
|
63
|
-
def phraser
|
64
|
-
ListPhraser
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RailsEventStore
|
4
|
-
module RSpec
|
5
|
-
class Publish
|
6
|
-
def in(event_store)
|
7
|
-
@event_store = event_store
|
8
|
-
self
|
9
|
-
end
|
10
|
-
|
11
|
-
def in_stream(stream)
|
12
|
-
@stream = stream
|
13
|
-
self
|
14
|
-
end
|
15
|
-
|
16
|
-
def matches?(event_proc)
|
17
|
-
raise_event_store_not_set unless @event_store
|
18
|
-
spec = @event_store.read
|
19
|
-
spec = spec.stream(@stream) if @stream
|
20
|
-
last_event_before_block = spec.last
|
21
|
-
event_proc.call
|
22
|
-
spec = spec.from(last_event_before_block.event_id) if last_event_before_block
|
23
|
-
@published_events = spec.to_a
|
24
|
-
if match_events?
|
25
|
-
::RSpec::Matchers::BuiltIn::Include.new(*@expected).matches?(@published_events)
|
26
|
-
else
|
27
|
-
!@published_events.empty?
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def failure_message
|
32
|
-
if match_events?
|
33
|
-
<<-EOS
|
34
|
-
expected block to have published:
|
35
|
-
|
36
|
-
#{@expected}
|
37
|
-
|
38
|
-
#{"in stream #{@stream} " if @stream}but published:
|
39
|
-
|
40
|
-
#{@published_events}
|
41
|
-
EOS
|
42
|
-
else
|
43
|
-
"expected block to have published any events"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def failure_message_when_negated
|
48
|
-
if match_events?
|
49
|
-
<<-EOS
|
50
|
-
expected block not to have published:
|
51
|
-
|
52
|
-
#{@expected}
|
53
|
-
|
54
|
-
#{"in stream #{@stream} " if @stream}but published:
|
55
|
-
|
56
|
-
#{@published_events}
|
57
|
-
EOS
|
58
|
-
else
|
59
|
-
"expected block not to have published any events"
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def description
|
64
|
-
"publish events"
|
65
|
-
end
|
66
|
-
|
67
|
-
def supports_block_expectations?
|
68
|
-
true
|
69
|
-
end
|
70
|
-
|
71
|
-
private
|
72
|
-
|
73
|
-
def initialize(*expected)
|
74
|
-
@expected = expected
|
75
|
-
end
|
76
|
-
|
77
|
-
def match_events?
|
78
|
-
!@expected.empty?
|
79
|
-
end
|
80
|
-
|
81
|
-
def raise_event_store_not_set
|
82
|
-
raise SyntaxError, "You have to set the event store instance with `in`, e.g. `expect { ... }.to publish(an_event(MyEvent)).in(event_store)`"
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'rails_event_store/rspec/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = 'rails_event_store-rspec'
|
8
|
-
spec.version = RailsEventStore::RSpec::VERSION
|
9
|
-
spec.licenses = ['MIT']
|
10
|
-
spec.authors = ['Arkency']
|
11
|
-
spec.email = ['dev@arkency.com']
|
12
|
-
|
13
|
-
spec.summary = %q{RSpec matchers for RailsEventStore}
|
14
|
-
spec.homepage = 'https://railseventstore.org'
|
15
|
-
spec.metadata = {
|
16
|
-
"homepage_uri" => "https://railseventstore.org/",
|
17
|
-
"changelog_uri" => "https://github.com/RailsEventStore/rails_event_store/releases",
|
18
|
-
"source_code_uri" => "https://github.com/RailsEventStore/rails_event_store",
|
19
|
-
"bug_tracker_uri" => "https://github.com/RailsEventStore/rails_event_store/issues",
|
20
|
-
}
|
21
|
-
|
22
|
-
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
23
|
-
f.match(%r{^(test|spec|features)/})
|
24
|
-
end
|
25
|
-
spec.bindir = 'exe'
|
26
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
|
-
spec.require_paths = ['lib']
|
28
|
-
|
29
|
-
spec.add_runtime_dependency 'rspec', '~> 3.0'
|
30
|
-
spec.add_runtime_dependency 'diff-lcs', '>= 1.4.4'
|
31
|
-
end
|