Skip to content

Commit f65c9f3

Browse files
authored
Merge pull request #4 from openfoodfoundation/error-messages
Improve error message for n.times syntax
2 parents c1a4f59 + 0ac1381 commit f65c9f3

File tree

8 files changed

+171
-6
lines changed

8 files changed

+171
-6
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ jobs:
2121
ruby-version: ${{ matrix.ruby-version }}
2222
bundler-cache: true
2323
- run: bundle exec rspec
24+
- run: bundle exec rubocop

.rubocop.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
AllCops:
2+
NewCops: enable
3+
4+
Layout/LineLength:
5+
Max: 80 # default is 120
6+
7+
Metrics/BlockLength:
8+
AllowedMethods:
9+
# RSpec context block containing many smaller blocks:
10+
- Matchers.define
11+
# RSpec context block containing many smaller examples:
12+
- RSpec.describe
13+
14+
Style/BlockDelimiters:
15+
BracesRequiredMethods:
16+
# The RSpec expect syntax is prettier with braced blocks.
17+
- expect
18+
19+
Style/StringLiterals:
20+
# It's my preference to add or remove variable from strings without replacing
21+
# the outer quotes.
22+
EnforcedStyle: double_quotes
23+
24+
Style/TrailingCommaInArrayLiteral:
25+
# Consistent commas allow for adding and removing lines without affecting
26+
# other lines of arrays. Less editing, prettier diffs.
27+
EnforcedStyleForMultiline: consistent_comma
28+
29+
Style/TrailingCommaInHashLiteral:
30+
# Same reason as above.
31+
EnforcedStyleForMultiline: consistent_comma

Gemfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
# frozen_string_literal: true
2+
13
source "https://rubygems.org"
24
gemspec
35

46
gem "activerecord"
7+
gem "rubocop", require: false
58
gem "sqlite3"

Gemfile.lock

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ GEM
2424
minitest (>= 5.1)
2525
mutex_m
2626
tzinfo (~> 2.0)
27+
ast (2.4.2)
2728
base64 (0.2.0)
2829
bigdecimal (3.1.6)
2930
concurrent-ruby (1.2.3)
@@ -33,8 +34,18 @@ GEM
3334
ruby2_keywords
3435
i18n (1.14.1)
3536
concurrent-ruby (~> 1.0)
37+
json (2.7.2)
38+
language_server-protocol (3.17.0.3)
3639
minitest (5.22.2)
3740
mutex_m (0.2.0)
41+
parallel (1.24.0)
42+
parser (3.3.0.5)
43+
ast (~> 2.4.1)
44+
racc
45+
racc (1.7.3)
46+
rainbow (3.1.1)
47+
regexp_parser (2.9.0)
48+
rexml (3.2.6)
3849
rspec (3.13.0)
3950
rspec-core (~> 3.13.0)
4051
rspec-expectations (~> 3.13.0)
@@ -48,18 +59,34 @@ GEM
4859
diff-lcs (>= 1.2.0, < 2.0)
4960
rspec-support (~> 3.13.0)
5061
rspec-support (3.13.0)
62+
rubocop (1.63.1)
63+
json (~> 2.3)
64+
language_server-protocol (>= 3.17.0)
65+
parallel (~> 1.10)
66+
parser (>= 3.3.0.2)
67+
rainbow (>= 2.2.2, < 4.0)
68+
regexp_parser (>= 1.8, < 3.0)
69+
rexml (>= 3.2.5, < 4.0)
70+
rubocop-ast (>= 1.31.1, < 2.0)
71+
ruby-progressbar (~> 1.7)
72+
unicode-display_width (>= 2.4.0, < 3.0)
73+
rubocop-ast (1.31.2)
74+
parser (>= 3.3.0.4)
75+
ruby-progressbar (1.13.0)
5176
ruby2_keywords (0.0.5)
5277
sqlite3 (1.7.2-x86_64-linux)
5378
timeout (0.4.1)
5479
tzinfo (2.0.6)
5580
concurrent-ruby (~> 1.0)
81+
unicode-display_width (2.5.0)
5682

5783
PLATFORMS
5884
x86_64-linux
5985

6086
DEPENDENCIES
6187
activerecord
6288
rspec-sql!
89+
rubocop
6390
sqlite3
6491

6592
BUNDLED WITH

lib/rspec/sql.rb

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55

66
require_relative "sql/query_summary"
77

8+
# We are building within the RSpec namespace for consistency and convenience.
9+
# We are not part of the RSpec team though.
810
module RSpec
11+
# RSpec::Sql contains our code.
912
module Sql; end
1013

11-
RSpec::Matchers.define :query_database do |expected = nil|
14+
Matchers.define :query_database do |expected = nil|
1215
match do |block|
1316
@queries = scribe_queries(&block)
1417

@@ -28,6 +31,10 @@ module Sql; end
2831
end
2932

3033
failure_message do |_block|
34+
if expected.is_a?(Enumerator) && expected.inspect.match?(/:times>$/)
35+
expected = expected.size
36+
end
37+
3138
<<~MESSAGE
3239
Expected database queries: #{expected}
3340
Actual database queries: #{query_names}
@@ -41,7 +48,11 @@ module Sql; end
4148
end
4249

4350
failure_message_when_negated do |_block|
44-
"Expected no database queries but observed:\n\n#{query_descriptions.join("\n")}"
51+
<<~TXT
52+
Expected no database queries but observed:
53+
54+
#{query_descriptions.join("\n")}
55+
TXT
4556
end
4657

4758
def supports_block_expectations?
@@ -63,9 +74,9 @@ def query_summary
6374
def scribe_queries(&)
6475
queries = []
6576

66-
logger = ->(_name, _started, _finished, _unique_id, payload) {
77+
logger = lambda do |_name, _started, _finished, _unique_id, payload|
6778
queries << payload unless %w[CACHE SCHEMA].include?(payload[:name])
68-
}
79+
end
6980

7081
ActiveSupport::Notifications.subscribed(logger, "sql.active_record", &)
7182

lib/rspec/sql/query_summary.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
module RSpec
44
module Sql
5+
# Converts a list of queries into a summary hash.
56
class QuerySummary
6-
QUERY_TYPES = [:delete, :insert, :select, :update].freeze
7+
QUERY_TYPES = %i[delete insert select update].freeze
78

89
attr_reader :summary
910

rspec-sql.gemspec

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# frozen_string_literal: true
2+
13
Gem::Specification.new do |s|
24
s.name = "rspec-sql"
35
s.version = "0.0.1"
@@ -8,8 +10,9 @@ Gem::Specification.new do |s|
810
s.files = Dir["lib/**/*.rb"]
911
s.homepage = "https://github.com/openfoodfoundation/rspec-sql"
1012
s.license = "AGPL-3.0-or-later"
11-
s.required_ruby_version = '>= 3.1', '< 4'
13+
s.required_ruby_version = ">= 3.1", "< 4"
1214

1315
s.add_runtime_dependency "activesupport"
1416
s.add_runtime_dependency "rspec"
17+
s.metadata["rubygems_mfa_required"] = "true"
1518
end

spec/lib/rspec/sql_spec.rb

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,92 @@
6666
}
6767
)
6868
end
69+
70+
it "prints user-friendly message expecting a number" do
71+
message = error_message { expect { User.last }.to query_database 2 }
72+
expect(message).to eq <<~TXT
73+
Expected database queries: 2
74+
Actual database queries: ["User Load"]
75+
76+
Diff:
77+
@@ -1 +1 @@
78+
-2
79+
+["User Load"]
80+
81+
82+
Full query log:
83+
84+
User Load SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?
85+
TXT
86+
end
87+
88+
it "prints user-friendly message expecting x.times" do
89+
message = error_message { expect { User.last }.to query_database 2.times }
90+
expect(message).to eq <<~TXT
91+
Expected database queries: 2
92+
Actual database queries: ["User Load"]
93+
94+
Diff:
95+
@@ -1 +1 @@
96+
-2
97+
+["User Load"]
98+
99+
100+
Full query log:
101+
102+
User Load SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?
103+
TXT
104+
end
105+
106+
it "prints user-friendly message expecting list" do
107+
message = error_message do
108+
expect { User.last }.to query_database ["User Update"]
109+
end
110+
111+
expect(message).to eq <<~TXT
112+
Expected database queries: ["User Update"]
113+
Actual database queries: ["User Load"]
114+
115+
Diff:
116+
@@ -1 +1 @@
117+
-["User Update"]
118+
+["User Load"]
119+
120+
121+
Full query log:
122+
123+
User Load SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?
124+
TXT
125+
end
126+
127+
it "prints user-friendly message expecting summary" do
128+
message = error_message do
129+
expect { User.last }.to query_database(
130+
update: { user: 1 }
131+
)
132+
end
133+
134+
# This message could be better but nobody has asked for it yet.
135+
expect(message).to eq <<~TXT
136+
Expected database queries: {:update=>{:user=>1}}
137+
Actual database queries: ["User Load"]
138+
139+
Diff:
140+
@@ -1 +1 @@
141+
-:update => {:user=>1},
142+
+["User Load"]
143+
144+
145+
Full query log:
146+
147+
User Load SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?
148+
TXT
149+
end
150+
151+
def error_message
152+
yield
153+
rescue RSpec::Expectations::ExpectationNotMetError => e
154+
# Remove colours and trailing whitespace from message:
155+
e.message.gsub(/\e\[(\d+)m/, "").gsub(/ $/, "")
156+
end
69157
end

0 commit comments

Comments
 (0)