rspec-activerecord-expectations 2.1.1 → 2.2.0

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: a6e24b218adcab0f1e6fb117d66463a2cdf60996fe5c16f60d48f8efd37c3259
4
- data.tar.gz: 4f0acb5f4c489f4b2ded11b7d27a1bec613d231b04d836f651a26daf1bdb5bb1
3
+ metadata.gz: 3205b050d5f2164b5bc72de9fe29a0f6d988cd869ecd6703a09b83b2550bb02e
4
+ data.tar.gz: d43d363888f5c8f85dc551fae7d1381a945ac304c597192544ffd1506d1f7495
5
5
  SHA512:
6
- metadata.gz: d077a6aa43e9f243a4be0d5b4db338a2aa3272e49974b8cc9b987499571de846e6f5cbc4c9d1f4d3d58d50b1d91ce3d361f2719ee3073ae8eeeee589a62d3e8c
7
- data.tar.gz: 4473b4f016d10ca617e4ef5b3b1550c44903a170e9fde1291a88097a264028a0e21383fa37324f063c9529412c52e70e6fb24fab9e7a6df2382568f6a763fbc5
6
+ metadata.gz: a98cfac5ba127c3e5f7bd2b42ef48fa56e6750e75d0ab841988b076a2a39c0ca13e5d67e534020fd81af3b7885cba3d192c23a2fbb0b4ccd0d8e725e3cafb147
7
+ data.tar.gz: 65347df27d406531b1ea594bfe9a3d9b6405c75ad5f8be5c3f52f668e3d976e0e73c5e1560caeb308cb203b73547ab18c0ffd758aff0e913a9f010665a0a6595
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.2.0] - 2022-01-14
4
+ - Adds transaction matcher to verify that code was executed within a
5
+ transaction at minimum
6
+ - Transaction matcher also allows for commits and rollbacks
7
+ - Update README for accompanying functionality
8
+
3
9
  ## [2.1.1] - 2022-01-12
4
10
  - Gemspec is really generated using the version of ruby that's locally in use.
5
11
  Update that build artifact to use non-java dependencies.
data/README.md CHANGED
@@ -181,7 +181,57 @@ expect {}.to execute.exactly(20).transaction_queries
181
181
  categories, nor are queries that load the DB schema.
182
182
 
183
183
  **Note:** Destroy and delete queries are both condensed into the matcher for
184
- `destroy_queries`.
184
+ the errorthe error `destroy_queries`.
185
+
186
+ ## Transaction Management
187
+
188
+ Sometimes, it makes sense to monitor whether database transactions were
189
+ successful or not. This is very similar to using `expect{}.to change(SomeModel,
190
+ :count)` in a spec, but nonetheless it can be useful to assert transactions
191
+ themselves. Some assertions are available for this purpose.
192
+
193
+ ```ruby
194
+ expect {}.to execute_a_transaction
195
+ expect {}.to rollback_a_transaction
196
+ expect {}.to roll_back_a_transaction
197
+ expect {}.to commit_a_transaction
198
+ ```
199
+
200
+ A complication to this scheme is that Rails tries not to make unnecessary database
201
+ calls, which means that attempting to save a model that has failing validations
202
+ won't actually attempt to save to the database.
203
+
204
+ ```ruby
205
+ expect {
206
+ MyClass.create!(required_field: nil)
207
+ }.to rollback_a_transaction
208
+ ```
209
+
210
+ This assertion will fail, as `create!` will never make it as far as the
211
+ database. That said, if you manually create a transaction, _and you select
212
+ data within that transaction_, you may assert a rollback.
213
+
214
+ ```ruby
215
+ expect {
216
+ MyClass.first # triggers the transaction
217
+ MyClass.create!(required_field: nil)
218
+ }.to rollback_a_transaction
219
+ ```
220
+
221
+ It you need to make transaction-related assertions of this sort, your best bet
222
+ may be to assert that a commit statement was _not_ issued.
223
+
224
+ ```ruby
225
+ expect do
226
+ MyClass.create!(required_field: nil)
227
+ rescue
228
+ # NOOP
229
+ end.not_to rollback_a_transaction
230
+ ```
231
+
232
+ Note that ActiveRecord will not only roll back the transaction, but also
233
+ re-raise errors. As such, it's necessary in this example to rescue that
234
+ error in order for the test to fail.
185
235
 
186
236
  ## Future Planned Functionality
187
237
 
@@ -194,14 +244,13 @@ expect {}.to execute.at_least(2).load_queries("Audited::Audit")
194
244
  expect {}.to execute.at_least(2).activerecord_queries
195
245
  expect {}.to execute.at_least(2).hand_rolled_queries
196
246
 
197
- expect {}.not_to rollback_transaction.exactly(5).times
198
- expect {}.not_to commit_transaction.once
199
- expect {}.to run_a_transaction
200
-
201
247
  expect {}.to create.exactly(5).of_type(User)
202
248
  expect {}.to insert.exactly(5).subscription_changes
203
249
  expect {}.to update.exactly(2).of_any_type
204
250
  expect {}.to delete.exactly(2).of_any_type
251
+
252
+ expect {}.to commit_a_transaction.once
253
+ expect {}.to rollback_a_transaction.exactly(5).times
205
254
  ```
206
255
 
207
256
  - warn if we smite any built in methods (or methods from other libs)
@@ -0,0 +1,70 @@
1
+ module RSpec::ActiveRecord::Expectations
2
+ module Matchers
3
+ class TransactionMatcher
4
+ def initialize(transaction_type)
5
+ @collector = Collector.new
6
+ @transaction = transaction_type
7
+ end
8
+
9
+ def supports_block_expectations?
10
+ true
11
+ end
12
+
13
+ def matches?(block)
14
+ block.call
15
+
16
+ @count = @collector.queries_of_type(@transaction)
17
+ @count > 0
18
+ end
19
+
20
+ def failure_message
21
+ type_msg = case @transaction
22
+ when :transaction_queries
23
+ "execute a transaction"
24
+ when :rollback_queries
25
+ "roll back a transaction"
26
+ when :commit_queries
27
+ "commit a transaction"
28
+ end
29
+
30
+ "expected block to #{type_msg}, but it didn't do so"
31
+ end
32
+
33
+ def failure_message_when_negated
34
+ if @count == 1
35
+ negated_message_singular
36
+ else
37
+ negated_message_plural
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def negated_message_singular
44
+ pre_msg, post_msg = case @transaction
45
+ when :transaction_queries
46
+ ["execute a transaction", "executed one"]
47
+ when :rollback_queries
48
+ ["roll back a transaction", "rolled one back"]
49
+ when :commit_queries
50
+ ["commit a transaction", "committed one"]
51
+ end
52
+
53
+ "expected block not to #{pre_msg}, but it #{post_msg}"
54
+ end
55
+
56
+ def negated_message_plural
57
+ pre_msg, post_msg = case @transaction
58
+ when :transaction_queries
59
+ ["execute a transaction", "executed #{@count} transactions"]
60
+ when :rollback_queries
61
+ ["roll back a transaction", "rolled back #{@count} transactions"]
62
+ when :commit_queries
63
+ ["commit a transaction", "committed #{@count} transactions"]
64
+ end
65
+
66
+ "expected block not to #{pre_msg}, but it #{post_msg}"
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,14 +1,19 @@
1
1
  module RSpec::ActiveRecord::Expectations
2
2
  class QueryInspector
3
3
  def self.valid_query_types
4
- [:queries, :schema_queries, :transaction_queries, :insert_queries,
5
- :load_queries, :destroy_queries, :exists_queries]
4
+ [:queries, :schema_queries, :insert_queries, :load_queries,
5
+ :destroy_queries, :exists_queries,
6
+ :transaction_queries, :commit_queries, :rollback_queries]
6
7
  end
7
8
 
8
9
  def categorize(query)
9
10
  if query[:name] == "SCHEMA"
10
11
  [:schema_queries]
11
- elsif query[:name] == "TRANSACTION" || query[:sql] =~ /^begin/i || query[:sql] =~ /^commit/i
12
+ elsif query[:sql] =~ /^commit/i
13
+ [:commit_queries]
14
+ elsif query[:sql] =~ /^rollback/i
15
+ [:rollback_queries]
16
+ elsif query[:name] == "TRANSACTION"
12
17
  [:transaction_queries]
13
18
  elsif query[:name] =~ /Create$/
14
19
  [:queries, :insert_queries]
@@ -8,6 +8,22 @@ module RSpec
8
8
  def repeatedly_load(klass)
9
9
  Matchers::LoadMatcher.new(klass)
10
10
  end
11
+
12
+ def execute_a_transaction
13
+ Matchers::TransactionMatcher.new(:transaction_queries)
14
+ end
15
+
16
+ def rollback_a_transaction
17
+ Matchers::TransactionMatcher.new(:rollback_queries)
18
+ end
19
+
20
+ def roll_back_a_transaction
21
+ Matchers::TransactionMatcher.new(:rollback_queries)
22
+ end
23
+
24
+ def commit_a_transaction
25
+ Matchers::TransactionMatcher.new(:commit_queries)
26
+ end
11
27
  end
12
28
  end
13
29
  end
@@ -17,3 +33,4 @@ require_relative 'expectations/query_inspector'
17
33
  require_relative 'expectations/collector'
18
34
  require_relative 'expectations/matchers/query_count_matcher'
19
35
  require_relative 'expectations/matchers/load_matcher'
36
+ require_relative 'expectations/matchers/transaction_matcher'
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "rspec-activerecord-expectations"
3
- spec.version = '2.1.1'
3
+ spec.version = '2.2.0'
4
4
  spec.authors = ["Joseph Mastey"]
5
5
  spec.email = ["hello@joemastey.com"]
6
6
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-activerecord-expectations
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joseph Mastey
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-13 00:00:00.000000000 Z
11
+ date: 2022-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -104,6 +104,7 @@ files:
104
104
  - lib/rspec/activerecord/expectations/errors.rb
105
105
  - lib/rspec/activerecord/expectations/matchers/load_matcher.rb
106
106
  - lib/rspec/activerecord/expectations/matchers/query_count_matcher.rb
107
+ - lib/rspec/activerecord/expectations/matchers/transaction_matcher.rb
107
108
  - lib/rspec/activerecord/expectations/query_inspector.rb
108
109
  - rspec-activerecord-expectations.gemspec
109
110
  homepage: https://github.com/jmmastey/rspec-activerecord-expectations