json_matchers 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|