Skip to content

Commit ee1349d

Browse files
committed
Configure matcher to record_errors
Closes [#51]. By default, `JsonMatchers.configuration.options[:record_errors] = true`. Extract `JsonMatchers::Validator` to encapsulate error reporting behavior. `JSON::Validator` exposes a `#validate!` method that will raise on validation failures, and a `#fully_validate!` method that won't raise, but will return an array of error messages instead. [#51]: #51
1 parent 871bb40 commit ee1349d

File tree

5 files changed

+82
-35
lines changed

5 files changed

+82
-35
lines changed

NEWS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
master
22
======
33

4+
* Default `record_errors: true` [#52]
5+
* Add support for configuring `record_errors` [#51]
6+
7+
[#52]: https://github.com/thoughtbot/json_matchers/pull/52
8+
[#51]: https://github.com/thoughtbot/json_matchers/pull/51
9+
410
0.6.3
511
=====
612

lib/json_matchers/configuration.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ class Configuration
1111
attr_reader :options
1212

1313
def initialize
14-
@options = {}
14+
@options = {
15+
record_errors: true,
16+
}
1517
end
1618
end
1719
end

lib/json_matchers/matcher.rb

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
require "json-schema"
2-
require "json_matchers/payload"
2+
require "json_matchers/validator"
33

44
module JsonMatchers
55
class Matcher
@@ -9,47 +9,37 @@ def initialize(schema_path, options = {})
99
end
1010

1111
def matches?(response)
12-
# validate! will not raise and will always return true if you configure
13-
# the validator to record errors, so we must instead inspect
14-
# fully_validate's errors response
15-
if options[:record_errors]
16-
errors = JSON::Validator.fully_validate(
17-
schema_path.to_s,
18-
Payload.new(response).to_s,
19-
options,
20-
)
21-
22-
# errors is an array, but it will always only return a single item
23-
if errors.any?
24-
@validation_failure_message = errors.first
25-
false
26-
else
27-
true
28-
end
29-
else
30-
JSON::Validator.validate!(
31-
schema_path.to_s,
32-
Payload.new(response).to_s,
33-
options,
34-
)
35-
end
36-
rescue JSON::Schema::ValidationError => ex
37-
@validation_failure_message = ex.message
12+
validator = build_validator(response)
13+
14+
self.errors = validator.validate!
15+
16+
errors.empty?
17+
rescue JSON::Schema::ValidationError => error
18+
self.errors = [error.message]
3819
false
3920
rescue JSON::Schema::JsonParseError
4021
raise InvalidSchemaError
4122
end
4223

4324
def validation_failure_message
44-
@validation_failure_message.to_s
25+
errors.first.to_s
4526
end
4627

4728
private
4829

4930
attr_reader :schema_path, :options
31+
attr_accessor :errors
5032

5133
def default_options
5234
JsonMatchers.configuration.options || {}
5335
end
36+
37+
def build_validator(response)
38+
Validator.new(
39+
options: options,
40+
response: response,
41+
schema_path: schema_path,
42+
)
43+
end
5444
end
5545
end

lib/json_matchers/validator.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
require "json-schema"
2+
require "json_matchers/payload"
3+
4+
module JsonMatchers
5+
class Validator
6+
def initialize(options:, response:, schema_path:)
7+
@options = options.dup
8+
@payload = Payload.new(response).to_s
9+
@schema_path = schema_path.to_s
10+
end
11+
12+
def validate!
13+
if recording_errors?
14+
validate_recording_errors
15+
else
16+
validate
17+
end
18+
end
19+
20+
private
21+
22+
attr_reader :options, :payload, :schema_path
23+
24+
def recording_errors?
25+
options.fetch(:record_errors, false)
26+
end
27+
28+
def validate_recording_errors
29+
JSON::Validator.fully_validate(schema_path, payload, options)
30+
end
31+
32+
def validate
33+
JSON::Validator.validate!(schema_path, payload, options)
34+
35+
[]
36+
end
37+
end
38+
end

spec/json_matchers/match_response_schema_spec.rb

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,24 @@
159159
end
160160

161161
context "when configured to record errors" do
162-
it "fails when the body is missing a required property" do
162+
it "includes the reasons for failure in the exception's message" do
163163
with_options(record_errors: true) do
164-
create_schema("foo_schema",
165-
"type" => "object",
166-
"required" => ["foo"])
167-
168-
expect(response_for({})).not_to match_response_schema("foo_schema")
164+
create_schema("foo_schema", {
165+
"type" => "object",
166+
"properties" => {
167+
"username" => {
168+
"allOf": [
169+
{ "type": "string" },
170+
{ "minLength": 5 }
171+
]
172+
}
173+
}
174+
})
175+
invalid_payload = response_for({ "username" => "foo" })
176+
177+
expect {
178+
expect(invalid_payload).to match_response_schema("foo_schema")
179+
}.to raise_error(/minimum/)
169180
end
170181
end
171182
end

0 commit comments

Comments
 (0)