Skip to content

Commit 31b2c55

Browse files
authored
Merge pull request #5 from openfoodfoundation/error-messages
Improve failure messages when not expecting a list
2 parents 0809b91 + e5325d6 commit 31b2c55

File tree

4 files changed

+104
-41
lines changed

4 files changed

+104
-41
lines changed

lib/rspec/sql.rb

+19-24
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
require "active_support"
44
require "rspec"
55

6-
require_relative "sql/query_summary"
6+
require_relative "sql/query_matcher"
77

88
# We are building within the RSpec namespace for consistency and convenience.
99
# We are not part of the RSpec team though.
@@ -14,32 +14,22 @@ module Sql; end
1414
Matchers.define :query_database do |expected = nil|
1515
match do |block|
1616
@queries = scribe_queries(&block)
17+
@matcher = Sql::QueryMatcher.new(@queries, expected)
18+
expected = matcher.expected
1719

18-
if expected.nil?
19-
!@queries.empty?
20-
elsif expected.is_a?(Integer)
21-
@queries.size == expected
22-
elsif expected.is_a?(Enumerator) && expected.inspect.match?(/:times>$/)
23-
@queries.size == expected.size
24-
elsif expected.is_a?(Array)
25-
query_names == expected
26-
elsif expected.is_a?(Hash)
27-
query_summary == expected
28-
else
29-
raise "What are you expecting?"
30-
end
20+
matcher.matches?
3121
end
3222

3323
failure_message do |_block|
34-
if expected.is_a?(Enumerator) && expected.inspect.match?(/:times>$/)
35-
expected = expected.size
24+
if expected.nil?
25+
return "Expected at least one database query but observed none."
3626
end
3727

3828
<<~MESSAGE
3929
Expected database queries: #{expected}
40-
Actual database queries: #{query_names}
30+
Actual database queries: #{matcher.actual}
4131
42-
Diff: #{Expectations.differ.diff_as_object(query_names, expected)}
32+
Diff: #{diff(matcher.actual, expected)}
4333
4434
Full query log:
4535
@@ -59,16 +49,21 @@ def supports_block_expectations?
5949
true
6050
end
6151

62-
def query_names
63-
@queries.map { |q| q[:name] || q[:sql].split.take(2).join(" ") }
64-
end
65-
6652
def query_descriptions
6753
@queries.map { |q| "#{q[:name]} #{q[:sql]}" }
6854
end
6955

70-
def query_summary
71-
Sql::QuerySummary.new(@queries).summary
56+
def matcher
57+
@matcher
58+
end
59+
60+
def diff(actual, expected)
61+
if expected.is_a?(Numeric)
62+
change = actual - expected
63+
format("%+d", change)
64+
else
65+
Expectations.differ.diff_as_object(actual, expected)
66+
end
7267
end
7368

7469
def scribe_queries(&)

lib/rspec/sql/query_matcher.rb

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# frozen_string_literal: true
2+
3+
require_relative "query_summary"
4+
5+
module RSpec
6+
module Sql
7+
# Compares expectations with actual queries.
8+
class QueryMatcher
9+
attr_reader :expected
10+
11+
def initialize(queries, expected)
12+
@queries = queries
13+
@expected = sanitize_number(expected)
14+
end
15+
16+
def matches?
17+
# Simple presence validation.
18+
return !@queries.empty? if expected.nil?
19+
20+
actual == expected
21+
end
22+
23+
def actual
24+
@actual ||= actual_compared_to_expected
25+
end
26+
27+
private
28+
29+
# Support writing: `is_expected.to query_database 5.times`
30+
def sanitize_number(expected)
31+
if expected.is_a?(Enumerator) && expected.inspect.match?(/:times>$/)
32+
expected.size
33+
else
34+
expected
35+
end
36+
end
37+
38+
def actual_compared_to_expected
39+
case expected
40+
when Integer
41+
@queries.size
42+
when Array
43+
query_names
44+
when Hash
45+
query_summary
46+
else
47+
raise "What are you expecting?"
48+
end
49+
end
50+
51+
def query_names
52+
@queries.map { |q| q[:name] || q[:sql].split.take(2).join(" ") }
53+
end
54+
55+
def query_summary
56+
QuerySummary.new(@queries).summary
57+
end
58+
end
59+
end
60+
end

spec/lib/rspec/sql_spec.rb

+24-16
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,29 @@
6767
)
6868
end
6969

70-
it "prints user-friendly message expecting a number" do
71-
message = error_message { expect { User.last }.to query_database 2 }
70+
it "prints user-friendly message expecting nothing" do
71+
message = error_message { expect { User.last }.not_to query_database }
7272
expect(message).to eq <<~TXT
73-
Expected database queries: 2
74-
Actual database queries: ["User Load"]
73+
Expected no database queries but observed:
7574
76-
Diff:
77-
@@ -1 +1 @@
78-
-2
79-
+["User Load"]
75+
User Load SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?
76+
TXT
77+
end
78+
79+
it "prints user-friendly message expecting something" do
80+
message = error_message { expect { nil }.to query_database }
81+
expect(message).to eq(
82+
"Expected at least one database query but observed none."
83+
)
84+
end
85+
86+
it "prints user-friendly message expecting a number" do
87+
message = error_message { expect { User.last }.to query_database 0 }
88+
expect(message).to eq <<~TXT
89+
Expected database queries: 0
90+
Actual database queries: 1
8091
92+
Diff: +1
8193
8294
Full query log:
8395
@@ -89,13 +101,9 @@
89101
message = error_message { expect { User.last }.to query_database 2.times }
90102
expect(message).to eq <<~TXT
91103
Expected database queries: 2
92-
Actual database queries: ["User Load"]
93-
94-
Diff:
95-
@@ -1 +1 @@
96-
-2
97-
+["User Load"]
104+
Actual database queries: 1
98105
106+
Diff: -1
99107
100108
Full query log:
101109
@@ -134,12 +142,12 @@
134142
# This message could be better but nobody has asked for it yet.
135143
expect(message).to eq <<~TXT
136144
Expected database queries: {:update=>{:user=>1}}
137-
Actual database queries: ["User Load"]
145+
Actual database queries: {:select=>{:users=>1}}
138146
139147
Diff:
140148
@@ -1 +1 @@
141149
-:update => {:user=>1},
142-
+["User Load"]
150+
+:select => {:users=>1},
143151
144152
145153
Full query log:

spec/spec_helper.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
# Print the 10 slowest examples and example groups at the
8181
# end of the spec run, to help surface which specs are running
8282
# particularly slow.
83-
config.profile_examples = 10
83+
# config.profile_examples = 10
8484

8585
# Run specs in random order to surface order dependencies. If you find an
8686
# order dependency and want to debug it, you can fix the order by providing

0 commit comments

Comments
 (0)