stenotype 0.1.15 → 0.1.16

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a42b44b8b7a3c69fe9bfc179aaef8e274c67ace47d3609edda524358ff59d6ec
4
- data.tar.gz: 58b3185d8391de7473da08bc9ffb4de8ca9ca37e8d948b8c7d26b14d3bd1a928
3
+ metadata.gz: 31a64803c8b2a343a441ce48a26d5b14e5aa55792d718fe2afb236f0589507ca
4
+ data.tar.gz: 999e4ae1554d49663ac4b8e8cecd94507cde51cfa494c28ebf21fab4240eb41a
5
5
  SHA512:
6
- metadata.gz: 3578df8a2213ad6bfff4c8be71f902fba440ceed806e7b2cd4a3a7c443194e5abf11cc624f1466768f1a845e6a3696e108879e1524de5be553435b5fc443cc37
7
- data.tar.gz: 2550d63b410c460b663562d453b97659dc014fde50cd250949530e210d9dc80cd251964858f90aa331de3303fb3b534f1601444c1208fdd7739ec309bb505e3c
6
+ metadata.gz: a001057b435a76475cb49deb9a73601c2144a3468578d0a68f188ccad85598678a0b5909cd3f32f31b8b04bda42c284b8cb5d54b7423663a79beefb6afcaaf61
7
+ data.tar.gz: a3f20a7345504675073ad48b48fd3dfb73018bd3d65d1855a28e0224a61a1a9274aaf39bfa483de465b95a82915a616f7c9987986be28a7c3d1f2f1992f3c6d3
@@ -1,5 +1,8 @@
1
1
  # Changelog
2
2
 
3
+ ### 0.1.16
4
+ * Add rspec matchers to use in client code.
5
+
3
6
  ### 0.1.15
4
7
  * Updates readme.
5
8
 
data/README.md CHANGED
@@ -275,6 +275,48 @@ end
275
275
 
276
276
  You do not have to manually register the context handler since it happens upon inheriting from `Stenotype::ContextHandlers::Base`
277
277
 
278
+ ## Testing
279
+
280
+ Stenotype currently supports RSpec integration. To be able to test even emission you can use a predefined matcher by adding the following to spec helper:
281
+
282
+ ```ruby
283
+ RSpec.configure do |config|
284
+ config.around(:each, type: :stenotype_event) do |example|
285
+ require 'stenotype/adapters/test_adapter'
286
+
287
+ config.include Stenotype::Test::Matchers
288
+
289
+ RSpec::Mocks.with_temporary_scope do
290
+ allow(Stenotype.config).to receive(:targets).and_return(Array.wrap(Stenotype::Adapters::TestAdapter.new))
291
+ example.run
292
+ allow(Stenotype.config).to receive(:targets).and_call_original
293
+ end
294
+ end
295
+ end
296
+ ```
297
+
298
+ After adding the configuration you can use the matchers:
299
+ ```ruby
300
+ class Example
301
+ include Stenotype::Emitter
302
+
303
+ def trigger
304
+ emit_event(:user_subscription)
305
+ end
306
+ end
307
+
308
+ RSpec.describe Stenotype::Emitter do
309
+ describe "POST #create" do
310
+ subject(:post) { Example.new.trigger }
311
+
312
+ it "emits a user_subscription event", type: :stenotype_event do
313
+ expect { post }.to emit_an_event(:user_subscription).
314
+ with_arguments_including({ uuid: "abcd" }).
315
+ exactly(1).times
316
+ end
317
+ end
318
+ end
319
+ ```
278
320
 
279
321
  ## Development
280
322
 
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stenotype
4
+ module Adapters
5
+ class TestAdapter < Base
6
+ attr_reader :buffer
7
+
8
+ def initialize(*_)
9
+ @buffer = Array.new
10
+ super()
11
+ end
12
+
13
+ #
14
+ # @param event_data {Sting} The data to be published
15
+ # @param additional_attrs {Hash} The list of additional event attributes
16
+ #
17
+ def publish(event_data, **additional_attrs)
18
+ buffer << parse(event_data)
19
+ end
20
+
21
+ #
22
+ # Clears the buffer
23
+ #
24
+ def flush!
25
+ buffer.clear
26
+ end
27
+
28
+ private
29
+
30
+ def parse(event_data)
31
+ JSON.parse(event_data)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ module Stenotype
5
+ module Test
6
+ module Matchers
7
+ extend RSpec::Matchers::DSL
8
+
9
+ class DiffSizeMatchesExpectation
10
+ attr_reader :matching_events, :expected_count
11
+
12
+ def initialize(matching_events, expected_count)
13
+ @matching_events = matching_events
14
+ @expected_count = expected_count
15
+ end
16
+
17
+ def failure_message
18
+ "expected to see #{expected_count} event(s) but got #{matching_events.count} event(s)."
19
+ end
20
+
21
+ def matches?
22
+ matching_events.count == expected_count
23
+ end
24
+ end
25
+
26
+ class EventHasExpectedArguments
27
+ attr_reader :matching_events, :expected_arguments
28
+
29
+ def initialize(matching_events, expected_arguments)
30
+ @matching_events = matching_events
31
+ @expected_arguments = stringify_keys(expected_arguments)
32
+ end
33
+
34
+ def matches?
35
+ return false if multiple_events?
36
+
37
+ (expected_arguments.to_a - matching_event.to_a).empty?
38
+ end
39
+
40
+ def failure_message
41
+ if multiple_events?
42
+ "more than one event with given event name has been emitted. Can not match event arguments"
43
+ else
44
+ "expected to see all attributes from #{expected_arguments} to be included in event attributes but got #{matching_event}"
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def multiple_events?
51
+ matching_events.size > 1
52
+ end
53
+
54
+ def matching_event
55
+ matching_events.first
56
+ end
57
+
58
+ def stringify_keys(hash)
59
+ hash.transform_keys(&:to_s)
60
+ end
61
+ end
62
+
63
+ class EventEmitted
64
+ attr_reader :matching_events, :expected_event_name
65
+
66
+ def initialize(matching_events, expected_event_name)
67
+ @matching_events = matching_events
68
+ @expected_event_name = expected_event_name
69
+ end
70
+
71
+ def matches?
72
+ matching_events.any?
73
+ end
74
+
75
+ def failure_message
76
+ "expected to see a '#{expected_event_name}' event but got nothing"
77
+ end
78
+ end
79
+
80
+ matcher :emit_an_event do |expected_event_name, *_|
81
+ supports_block_expectations
82
+
83
+ match do |emitting_event_block|
84
+ @emitting_event_block = emitting_event_block
85
+
86
+ partial_matchers << EventEmitted.new(matching_events, expected_event_name)
87
+ partial_matchers << EventHasExpectedArguments.new(matching_events, @arguments_should_include) if should_validate_events_count?
88
+ partial_matchers << DiffSizeMatchesExpectation.new(matching_events, @matching_events_count) if should_validate_attributes?
89
+
90
+ return first_failure.nil?
91
+ end
92
+
93
+ chain(:with_arguments_including) { |**args| @arguments_should_include = args }
94
+ chain(:exactly) { |times| @matching_events_count = times }
95
+
96
+ # noop for syntatic sugar
97
+ chain(:times) {}
98
+ chain(:time) {}
99
+
100
+ def matching_events
101
+ @matching_events ||= begin
102
+ buffer_before_emit = stenotype_event_buffer.dup
103
+ @emitting_event_block.call
104
+ buffer_after_emit = stenotype_event_buffer.dup
105
+
106
+ diff = buffer_after_emit - buffer_before_emit
107
+ diff.select { |event| event["name"] == expected_event_name.to_s }
108
+ end
109
+ end
110
+
111
+ def partial_matchers
112
+ @partial_matchers ||= []
113
+ end
114
+
115
+ def first_failure
116
+ @first_failure ||= partial_matchers.detect { |matcher| !matcher.matches? }
117
+ end
118
+
119
+ failure_message do
120
+ return super() unless first_failure
121
+
122
+ first_failure.failure_message
123
+ end
124
+
125
+ private
126
+
127
+ def should_validate_events_count?
128
+ @matching_events_count.present?
129
+ end
130
+
131
+ def should_validate_attributes?
132
+ @arguments_should_include.present?
133
+ end
134
+
135
+ def stenotype_event_buffer
136
+ stenotype_event_target.buffer
137
+ end
138
+
139
+ def stenotype_event_target
140
+ Stenotype.config.targets.first
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Stenotype
4
4
  # :nodoc:
5
- VERSION = "0.1.15"
5
+ VERSION = "0.1.16"
6
6
  # :nodoc:
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stenotype
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.15
4
+ version: 0.1.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Kapitonov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-20 00:00:00.000000000 Z
11
+ date: 2020-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -268,6 +268,7 @@ files:
268
268
  - lib/stenotype/adapters/base.rb
269
269
  - lib/stenotype/adapters/google_cloud.rb
270
270
  - lib/stenotype/adapters/stdout_adapter.rb
271
+ - lib/stenotype/adapters/test_adapter.rb
271
272
  - lib/stenotype/at_exit.rb
272
273
  - lib/stenotype/configuration.rb
273
274
  - lib/stenotype/context_handlers.rb
@@ -283,6 +284,7 @@ files:
283
284
  - lib/stenotype/frameworks/rails/action_controller.rb
284
285
  - lib/stenotype/frameworks/rails/active_job.rb
285
286
  - lib/stenotype/railtie.rb
287
+ - lib/stenotype/test/matchers.rb
286
288
  - lib/stenotype/version.rb
287
289
  - stenotype.gemspec
288
290
  homepage: https://github.com/Freshly/stenotype