stenotype 0.1.15 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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