json_matchers 0.9.0 → 0.10.0
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 +4 -4
- data/.travis.yml +3 -1
- data/NEWS.md +9 -0
- data/README.md +104 -81
- data/json_matchers.gemspec +1 -1
- data/lib/json_matchers.rb +2 -2
- data/lib/json_matchers/assertion.rb +5 -5
- data/lib/json_matchers/matcher.rb +17 -20
- data/lib/json_matchers/parser.rb +21 -0
- data/lib/json_matchers/payload.rb +4 -0
- data/lib/json_matchers/rspec.rb +2 -14
- data/lib/json_matchers/validator.rb +17 -20
- data/lib/json_matchers/version.rb +1 -1
- data/spec/factories.rb +53 -17
- data/spec/json_matchers/match_json_schema_spec.rb +53 -77
- data/spec/support/fake_response.rb +1 -1
- data/spec/support/file_helpers.rb +0 -1
- data/test/json_matchers/minitest/assertions_test.rb +55 -29
- metadata +9 -13
- data/lib/json_matchers/configuration.rb +0 -27
- data/spec/json_matchers/configuration_spec.rb +0 -9
- data/spec/support/configuration.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03b79f9a5c8394f6e8ccbd26d6c066519e5d2a25ad6b623765a48f524ba38bf0
|
4
|
+
data.tar.gz: 00421a6718fff3b21d1c50382ea5b9d5f855dbfe4d2522dbf50db217f2993b8f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b4cc33ad05676e0ac2133c79d627ece2994d0a21878ad6269c3145081d3cf1fe0e193928e1ca312660baa418b69f5cd33661aa0f070301d50f51436b72d3c0a
|
7
|
+
data.tar.gz: 830aa3570c9ae06fcd3986323d2dd0a3763c7fd91c62e09cf7029e184612ec15c5227fa706afbfe3cb8471c61c4f8dd85fa2cea68f9fd5edb704f7c7bfdbfffc
|
data/.travis.yml
CHANGED
data/NEWS.md
CHANGED
@@ -1,6 +1,15 @@
|
|
1
1
|
master
|
2
2
|
======
|
3
3
|
|
4
|
+
0.10.0
|
5
|
+
======
|
6
|
+
|
7
|
+
* *BREAKING CHANGE* Implement the validation with the `json_schema` gem instead
|
8
|
+
of `json-schema`. [#31]
|
9
|
+
* *BREAKING CHANGE* - remove support for configuring validation options.
|
10
|
+
|
11
|
+
[#31]: https://github.com/thoughtbot/json_matchers/pull/31
|
12
|
+
|
4
13
|
0.9.0
|
5
14
|
=====
|
6
15
|
|
data/README.md
CHANGED
@@ -24,7 +24,7 @@ Or install it yourself as:
|
|
24
24
|
|
25
25
|
Inspired by [Validating JSON Schemas with an RSpec Matcher][original-blog-post].
|
26
26
|
|
27
|
-
[original-blog-post]: (
|
27
|
+
[original-blog-post]: (https://robots.thoughtbot.com/validating-json-schemas-with-an-rspec-matcher)
|
28
28
|
|
29
29
|
First, configure it in your test suite's helper file:
|
30
30
|
|
@@ -37,7 +37,7 @@ First, configure it in your test suite's helper file:
|
|
37
37
|
```ruby
|
38
38
|
require "json_matchers/rspec"
|
39
39
|
|
40
|
-
JsonMatchers.schema_root = "
|
40
|
+
JsonMatchers.schema_root = "spec/support/api/schemas"
|
41
41
|
```
|
42
42
|
|
43
43
|
#### Minitest
|
@@ -48,33 +48,34 @@ JsonMatchers.schema_root = "/spec/support/api/schemas"
|
|
48
48
|
require "minitest/autorun"
|
49
49
|
require "json_matchers/minitest/assertions"
|
50
50
|
|
51
|
-
JsonMatchers.schema_root = "
|
51
|
+
JsonMatchers.schema_root = "test/support/api/schemas"
|
52
52
|
|
53
53
|
Minitest::Test.send(:include, JsonMatchers::Minitest::Assertions)
|
54
54
|
```
|
55
55
|
|
56
56
|
### Declare
|
57
57
|
|
58
|
-
Declare your [JSON Schema](
|
58
|
+
Declare your [JSON Schema](https://json-schema.org/example1.html) in the schema
|
59
59
|
directory.
|
60
60
|
|
61
|
-
`spec/support/api/schemas/
|
61
|
+
`spec/support/api/schemas/location.json` or
|
62
|
+
`test/support/api/schemas/location.json`:
|
63
|
+
|
64
|
+
Define your [JSON Schema](https://json-schema.org/example1.html) in the schema
|
65
|
+
directory.
|
62
66
|
|
63
67
|
```json
|
64
68
|
{
|
69
|
+
"id": "https://json-schema.org/geo",
|
70
|
+
"$schema": "https://json-schema.org/draft-06/schema#",
|
71
|
+
"description": "A geographical coordinate",
|
65
72
|
"type": "object",
|
66
|
-
"required": ["posts"],
|
67
73
|
"properties": {
|
68
|
-
"
|
69
|
-
"type": "
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
"id": { "type": "integer" },
|
74
|
-
"title": { "type": "string" },
|
75
|
-
"body": { "type": "string" }
|
76
|
-
}
|
77
|
-
}
|
74
|
+
"latitude": {
|
75
|
+
"type": "number"
|
76
|
+
},
|
77
|
+
"longitude": {
|
78
|
+
"type": "number"
|
78
79
|
}
|
79
80
|
}
|
80
81
|
}
|
@@ -87,15 +88,15 @@ directory.
|
|
87
88
|
Validate a JSON response, a Hash, or a String against a JSON Schema with
|
88
89
|
`match_json_schema`:
|
89
90
|
|
90
|
-
`spec/requests/
|
91
|
+
`spec/requests/locations_spec.rb`
|
91
92
|
|
92
93
|
```ruby
|
93
|
-
describe "GET /
|
94
|
-
it "returns
|
95
|
-
get
|
94
|
+
describe "GET /locations" do
|
95
|
+
it "returns Locations" do
|
96
|
+
get locations_path, format: :json
|
96
97
|
|
97
98
|
expect(response.status).to eq 200
|
98
|
-
expect(response).to match_json_schema("
|
99
|
+
expect(response).to match_json_schema("locations")
|
99
100
|
end
|
100
101
|
end
|
101
102
|
```
|
@@ -105,107 +106,129 @@ end
|
|
105
106
|
Validate a JSON response, a Hash, or a String against a JSON Schema with
|
106
107
|
`assert_matches_json_schema`:
|
107
108
|
|
108
|
-
`test/integration/
|
109
|
+
`test/integration/locations_test.rb`
|
109
110
|
|
110
111
|
```ruby
|
111
|
-
def
|
112
|
-
get
|
112
|
+
def test_GET_posts_returns_Locations
|
113
|
+
get locations_path, format: :json
|
113
114
|
|
114
115
|
assert_equal response.status, 200
|
115
|
-
assert_matches_json_schema response, "
|
116
|
+
assert_matches_json_schema response, "locations"
|
116
117
|
end
|
117
118
|
```
|
118
119
|
|
119
|
-
###
|
120
|
+
### Embedding other Schemas
|
120
121
|
|
121
|
-
|
122
|
+
To re-use other schema definitions, include `$ref` keys that refer to their
|
123
|
+
definitions.
|
122
124
|
|
123
|
-
|
125
|
+
First, declare the singular version of your schema.
|
124
126
|
|
125
|
-
|
126
|
-
describe "GET /posts" do
|
127
|
-
it "returns Posts" do
|
128
|
-
get posts_path, format: :json
|
127
|
+
`spec/support/api/schemas/user.json`:
|
129
128
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
129
|
+
```json
|
130
|
+
{
|
131
|
+
"id": "file:/user.json#",
|
132
|
+
"type": "object",
|
133
|
+
"required": ["id"],
|
134
|
+
"properties": {
|
135
|
+
"id": { "type": "integer" },
|
136
|
+
"name": { "type": "string" },
|
137
|
+
"address": { "type": "string" },
|
138
|
+
},
|
139
|
+
}
|
134
140
|
```
|
135
141
|
|
136
|
-
|
137
|
-
|
138
|
-
[options]: https://github.com/ruby-json-schema/json-schema/blob/2.2.4/lib/json-schema/validator.rb#L160-L162
|
139
|
-
|
140
|
-
### DEPRECATED: Global matcher options
|
141
|
-
|
142
|
-
To configure the default options passed to *all* matchers, call
|
143
|
-
`JsonMatchers.configure`.
|
142
|
+
Then, when you declare your collection schema, reference your singular schemas.
|
144
143
|
|
145
|
-
`spec/support/
|
144
|
+
`spec/support/api/schemas/users/index.json`:
|
146
145
|
|
147
|
-
```
|
148
|
-
|
149
|
-
|
150
|
-
|
146
|
+
```json
|
147
|
+
{
|
148
|
+
"id": "file:/users/index.json#",
|
149
|
+
"type": "object",
|
150
|
+
"definitions": {
|
151
|
+
"users": {
|
152
|
+
"description": "A collection of users",
|
153
|
+
"example": [{ "id": "1" }],
|
154
|
+
"type": "array",
|
155
|
+
"items": {
|
156
|
+
"$ref": "file:/user.json#"
|
157
|
+
},
|
158
|
+
},
|
159
|
+
},
|
160
|
+
"required": ["users"],
|
161
|
+
"properties": {
|
162
|
+
"users": {
|
163
|
+
"$ref": "#/definitions/users"
|
164
|
+
}
|
165
|
+
},
|
166
|
+
}
|
151
167
|
```
|
152
168
|
|
153
|
-
|
169
|
+
NOTE: `$ref` resolves paths relative to the schema in question.
|
154
170
|
|
155
|
-
|
171
|
+
In this case `"user.json"` and `"users/index.json"` are resolved relative to
|
172
|
+
`"spec/support/api/schemas"` or `"test/support/api/schemas"`.
|
156
173
|
|
157
|
-
|
158
|
-
|
174
|
+
To learn more about `$ref`, check out
|
175
|
+
[Understanding JSON Schema Structuring][$ref].
|
159
176
|
|
160
|
-
|
177
|
+
[$ref]: https://spacetelescope.github.io/understanding-json-schema/structuring.html
|
161
178
|
|
162
|
-
|
179
|
+
### Declaring a schema in a Subdirectory
|
163
180
|
|
164
|
-
|
181
|
+
Nesting a schema within a subdirectory is also supported:
|
182
|
+
|
183
|
+
`spec/support/api/schemas/api/v1/location.json`:
|
165
184
|
|
166
|
-
`spec/support/api/schemas/post.json`:
|
167
185
|
|
168
186
|
```json
|
169
187
|
{
|
188
|
+
"id": "https://json-schema.org/geo",
|
189
|
+
"$schema": "https://json-schema.org/draft-06/schema#",
|
190
|
+
"description": "A geographical coordinate",
|
170
191
|
"type": "object",
|
171
|
-
"required": ["id", "title", "body"],
|
172
192
|
"properties": {
|
173
|
-
"
|
174
|
-
|
175
|
-
|
193
|
+
"latitude": {
|
194
|
+
"type": "number"
|
195
|
+
},
|
196
|
+
"longitude": {
|
197
|
+
"type": "number"
|
198
|
+
}
|
176
199
|
}
|
177
200
|
}
|
178
201
|
```
|
179
202
|
|
180
|
-
|
203
|
+
`spec/requests/api/v1/locations_spec.rb`:
|
181
204
|
|
182
|
-
|
205
|
+
```ruby
|
206
|
+
describe "GET api/v1/locations" do
|
207
|
+
it "returns Locations" do
|
208
|
+
get locations_path, format: :json
|
183
209
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
"properties": {
|
189
|
-
"posts": {
|
190
|
-
"type": "array",
|
191
|
-
"items": { "$ref": "post.json" }
|
192
|
-
}
|
193
|
-
}
|
194
|
-
}
|
210
|
+
expect(response.status).to eq 200
|
211
|
+
expect(response).to match_json_schema("api/v1/location")
|
212
|
+
end
|
213
|
+
end
|
195
214
|
```
|
196
215
|
|
197
|
-
|
216
|
+
## Configuration
|
217
|
+
|
218
|
+
By default, the schema directory is `spec/support/api/schemas`.
|
198
219
|
|
199
|
-
|
200
|
-
`"spec/support/api/schemas"`.
|
220
|
+
This can be configured via `JsonMatchers.schema_root`.
|
201
221
|
|
202
|
-
|
222
|
+
```ruby
|
223
|
+
# spec/support/json_matchers.rb
|
224
|
+
|
225
|
+
JsonMatchers.schema_root = "docs/api/schemas"
|
226
|
+
```
|
203
227
|
|
204
228
|
## Upgrading from `0.9.x`
|
205
229
|
|
206
|
-
|
207
|
-
|
208
|
-
will been removed.
|
230
|
+
Calls to `match_json_schema` and `match_response_schema` no longer accept
|
231
|
+
options, and `JsonMatchers.configure` has been removed.
|
209
232
|
|
210
233
|
## Contributing
|
211
234
|
|
data/json_matchers.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency("
|
21
|
+
spec.add_dependency("json_schema")
|
22
22
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.7"
|
24
24
|
spec.add_development_dependency "pry"
|
data/lib/json_matchers.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
+
require "pathname"
|
1
2
|
require "json_matchers/version"
|
2
|
-
require "json_matchers/configuration"
|
3
3
|
require "json_matchers/matcher"
|
4
4
|
require "json_matchers/errors"
|
5
5
|
|
@@ -9,6 +9,6 @@ module JsonMatchers
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.path_to_schema(schema_name)
|
12
|
-
Pathname(schema_root).join("#{schema_name}.json")
|
12
|
+
Pathname.new(schema_root).join("#{schema_name}.json")
|
13
13
|
end
|
14
14
|
end
|
@@ -5,16 +5,16 @@ require "json_matchers/matcher"
|
|
5
5
|
|
6
6
|
module JsonMatchers
|
7
7
|
class Assertion
|
8
|
-
def initialize(schema_name
|
9
|
-
@schema_name = schema_name
|
8
|
+
def initialize(schema_name)
|
9
|
+
@schema_name = schema_name.to_s
|
10
10
|
@schema_path = JsonMatchers.path_to_schema(schema_name)
|
11
|
-
@matcher = Matcher.new(schema_path
|
11
|
+
@matcher = Matcher.new(schema_path)
|
12
12
|
end
|
13
13
|
|
14
14
|
def valid?(json)
|
15
15
|
@payload = Payload.new(json)
|
16
16
|
|
17
|
-
matcher.matches?(payload
|
17
|
+
matcher.matches?(payload)
|
18
18
|
end
|
19
19
|
|
20
20
|
def valid_failure_message
|
@@ -58,7 +58,7 @@ not to match schema "#{schema_name}":
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def schema_body
|
61
|
-
|
61
|
+
schema_path.read
|
62
62
|
end
|
63
63
|
|
64
64
|
def format_json(json)
|
@@ -1,24 +1,18 @@
|
|
1
|
-
require "
|
1
|
+
require "json_schema"
|
2
|
+
require "json_matchers/parser"
|
2
3
|
require "json_matchers/validator"
|
3
4
|
|
4
5
|
module JsonMatchers
|
5
6
|
class Matcher
|
6
|
-
def initialize(schema_path
|
7
|
+
def initialize(schema_path)
|
7
8
|
@schema_path = schema_path
|
8
|
-
@
|
9
|
+
@document_store = build_and_populate_document_store
|
9
10
|
end
|
10
11
|
|
11
12
|
def matches?(payload)
|
12
|
-
|
13
|
-
|
14
|
-
self.errors = validator.validate!
|
13
|
+
self.errors = validator.validate(payload)
|
15
14
|
|
16
15
|
errors.empty?
|
17
|
-
rescue JSON::Schema::ValidationError => error
|
18
|
-
self.errors = [error.message]
|
19
|
-
false
|
20
|
-
rescue JSON::Schema::JsonParseError
|
21
|
-
raise InvalidSchemaError
|
22
16
|
end
|
23
17
|
|
24
18
|
def validation_failure_message
|
@@ -27,19 +21,22 @@ module JsonMatchers
|
|
27
21
|
|
28
22
|
private
|
29
23
|
|
30
|
-
attr_reader :schema_path, :options
|
31
24
|
attr_accessor :errors
|
25
|
+
attr_reader :document_store, :schema_path
|
32
26
|
|
33
|
-
def
|
34
|
-
|
27
|
+
def validator
|
28
|
+
Validator.new(schema_path: schema_path, document_store: document_store)
|
35
29
|
end
|
36
30
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
31
|
+
def build_and_populate_document_store
|
32
|
+
document_store = JsonSchema::DocumentStore.new
|
33
|
+
|
34
|
+
Dir.glob("#{JsonMatchers.schema_root}/**/*.json").
|
35
|
+
map { |path| Pathname.new(path) }.
|
36
|
+
map { |schema_path| Parser.new(schema_path).parse }.
|
37
|
+
each { |schema| document_store.add_schema(schema) }
|
38
|
+
|
39
|
+
document_store
|
43
40
|
end
|
44
41
|
end
|
45
42
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module JsonMatchers
|
2
|
+
class Parser
|
3
|
+
def initialize(schema_path)
|
4
|
+
@schema_path = schema_path
|
5
|
+
end
|
6
|
+
|
7
|
+
def parse
|
8
|
+
JsonSchema.parse!(schema_data)
|
9
|
+
rescue JSON::ParserError, JsonSchema::SchemaError => error
|
10
|
+
raise InvalidSchemaError.new(error)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
attr_reader :schema_path
|
16
|
+
|
17
|
+
def schema_data
|
18
|
+
JSON.parse(schema_path.read)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|