api_matchers 0.3.0 → 0.4.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 +6 -14
- data/.travis.yml +10 -0
- data/Gemfile +1 -1
- data/README.markdown +88 -75
- data/lib/api_matchers/core/find_in_json.rb +0 -1
- data/lib/api_matchers/response_body/have_xml_node.rb +16 -7
- data/lib/api_matchers/version.rb +1 -1
- data/spec/api_matchers/response_body/have_json_spec.rb +4 -0
- data/spec/api_matchers/response_body/have_xml_node_spec.rb +27 -0
- metadata +12 -11
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
Y2RhNTE5NzdmYTkwMjE0ZTVlM2EwZmM0ZjY2Y2U3MWQ2ZjA5OWIwMjY2NGVh
|
10
|
-
MmMzNGZhYmE0MzA0OGQ2NjQxYTgyNTJkMDI4YjhmNDJhZmM0NGNmMjAxZjQw
|
11
|
-
ZTRjM2NlNjI4ZDc5ZjYwZTM2ZTY0ZWIwYTQ1MzRiNmNlOGQ2ZDg=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
MzIyNmE0NmIwOGQxODRhMmJkN2ZmNmZkMTllOTFjMGJjMzc1MjQ3ZGY4MWZl
|
14
|
-
NWJjMGFiNjA3ZGRmYjZhMzBkOTAxNzgxM2JkOWQyNzUxNmI5NGRkYWRlMDA1
|
15
|
-
NTI4MWEzNDY1MGY0YzI2NzYzMGYxYzEwZDAwNDQyZGUyZTg3NjQ=
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 55a5fba1fb8dd8e0534a451e2db5af8662312b0e
|
4
|
+
data.tar.gz: dfe3690699a99aeffe353d50c7401a5eb741e084
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8a28c82e8bfeede2915149c45e89f0698c9c1600dfeaefb4ddda8e06ad0e88649144a59dd0f40cbe4f2b6b2465b5ea5ca0b205d41bcf8110a416354691d12582
|
7
|
+
data.tar.gz: 0d594066a2ba47024bb9cd1126578e0cef31f81a6b97ad009d8f7161f7290384a7a641127b35639b02043662f8b56f44acfeba49c14ed73f75999a6db521c443
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.markdown
CHANGED
@@ -1,30 +1,40 @@
|
|
1
|
-
# API Matchers
|
1
|
+
# API Matchers [](https://travis-ci.org/tomas-stefano/api_matchers)
|
2
2
|
|
3
|
-
Collection of RSpec matchers for
|
3
|
+
Collection of RSpec matchers for your API.
|
4
4
|
|
5
5
|
## Response Body Matchers
|
6
6
|
|
7
|
-
* have_node
|
8
|
-
* have_json_node
|
9
|
-
* have_xml_node
|
7
|
+
* `have_node`
|
8
|
+
* `have_json_node`
|
9
|
+
* `have_xml_node`
|
10
|
+
* `have_json`
|
10
11
|
|
11
|
-
|
12
|
+
## Response Status Matchers
|
12
13
|
|
13
|
-
*
|
14
|
-
* create_resource
|
15
|
-
* be_a_bad_request
|
16
|
-
* be_unauthorized
|
17
|
-
* be_internal_server_error
|
18
|
-
* be_not_found
|
14
|
+
* `be_ok`
|
15
|
+
* `create_resource`
|
16
|
+
* `be_a_bad_request`
|
17
|
+
* `be_unauthorized`
|
18
|
+
* `be_internal_server_error`
|
19
|
+
* `be_not_found`
|
19
20
|
|
20
|
-
|
21
|
+
## Other Matchers
|
21
22
|
|
22
|
-
* be_in_xml
|
23
|
-
*
|
23
|
+
* `be_in_xml`
|
24
|
+
* `be_in_json`
|
24
25
|
|
25
26
|
## Install
|
26
27
|
|
27
|
-
|
28
|
+
Include the gem to your test group in you Gemfile:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
group :test do
|
32
|
+
gem 'api_matchers'
|
33
|
+
# other gems
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
Or install it manually: `gem install api_matchers`.
|
28
38
|
|
29
39
|
## Usage
|
30
40
|
|
@@ -33,9 +43,9 @@ Collection of RSpec matchers for create your API.
|
|
33
43
|
To include all this matchers you need to include the APIMatchers::RSpecMatchers module:
|
34
44
|
|
35
45
|
```ruby
|
36
|
-
|
37
|
-
|
38
|
-
|
46
|
+
RSpec.configure do |config|
|
47
|
+
config.include APIMatchers::RSpecMatchers
|
48
|
+
end
|
39
49
|
```
|
40
50
|
|
41
51
|
### Have Node Matcher
|
@@ -46,33 +56,33 @@ The have_node matcher parse the actual and see if have the expcted node with the
|
|
46
56
|
You can verify if node exists:
|
47
57
|
|
48
58
|
```ruby
|
49
|
-
|
59
|
+
'{ "transaction": { "id": 54, "status": "paid" } }'.should have_node(:transaction)
|
50
60
|
```
|
51
61
|
|
52
62
|
Or if node exist with a value:
|
53
63
|
|
54
64
|
```ruby
|
55
|
-
|
65
|
+
'{ "transaction": { "id": 54, "status": "paid" } }'.should have_node(:id).with(54)
|
56
66
|
```
|
57
67
|
|
58
68
|
```ruby
|
59
|
-
|
69
|
+
'{ "error": "not_authorized" }'.should have_node(:error).with('not_authorized')
|
60
70
|
```
|
61
71
|
|
62
72
|
```ruby
|
63
|
-
|
73
|
+
'{"parcels":1 }'.should have_node(:parcels).with(1)
|
64
74
|
```
|
65
75
|
|
66
76
|
To see the json node and see if include a text, you can do this:
|
67
77
|
|
68
78
|
```ruby
|
69
|
-
|
79
|
+
'{"error": "Transaction error: Name cant be blank"}'.should have_node(:error).including_text("Transaction error")
|
70
80
|
```
|
71
81
|
|
72
82
|
You can verify boolean values too:
|
73
83
|
|
74
84
|
```ruby
|
75
|
-
|
85
|
+
'{"creditcard":true}'.should have_node(:creditcard).with(true)
|
76
86
|
```
|
77
87
|
|
78
88
|
### HAVE NODE Matcher Configuration
|
@@ -80,65 +90,67 @@ You can verify boolean values too:
|
|
80
90
|
You can configure if you want xml (JSON is the default):
|
81
91
|
|
82
92
|
```ruby
|
83
|
-
|
84
|
-
|
85
|
-
|
93
|
+
APIMatchers.setup do |config|
|
94
|
+
config.content_type = :xml
|
95
|
+
end
|
86
96
|
```
|
87
97
|
|
88
98
|
```ruby
|
89
|
-
|
99
|
+
'<transaction><id>200</id><status>paid</status></transaction>'.should have_node(:status)
|
90
100
|
```
|
91
101
|
|
92
|
-
Using the with method:
|
102
|
+
Using the `with` method:
|
93
103
|
|
94
104
|
```ruby
|
95
|
-
|
105
|
+
'<transaction><id>200</id><status>paid</status></transaction>'.should have_node(:status).with('paid')
|
96
106
|
```
|
97
107
|
|
98
|
-
Or you can use the
|
108
|
+
Or you can use the `have_xml_node` matcher:
|
99
109
|
|
100
110
|
```ruby
|
101
|
-
|
111
|
+
"<error>Transaction error: Name can't be blank</error>".should have_xml_node(:error).with("Transaction error: Name can't be blank")
|
102
112
|
```
|
103
113
|
|
104
114
|
To see the xml node and see if include a text, you can do this:
|
105
115
|
|
106
116
|
```ruby
|
107
|
-
|
117
|
+
"<error>Transaction error: Name can't be blank</error>".should have_xml_node(:error).including_text("Transaction error")
|
108
118
|
```
|
109
119
|
|
110
|
-
**If you work with xml and json in the same API,
|
120
|
+
**If you work with xml and json in the same API, check the have_json_node and have_xml_node matchers.**
|
111
121
|
|
112
|
-
You can configure the name of the method for example:
|
122
|
+
You can configure the name of the method and then you will be able to use *without* the **#body** method, for example:
|
113
123
|
|
114
124
|
```ruby
|
115
|
-
|
116
|
-
|
125
|
+
APIMatchers.setup do |config|
|
126
|
+
config.response_body_method = :body
|
127
|
+
end
|
128
|
+
|
129
|
+
response.should have_node(:foo).with('bar')
|
117
130
|
```
|
118
131
|
|
119
|
-
|
120
|
-
|
121
|
-
APIMatchers.setup do |config|
|
122
|
-
config.response_body_method = :body
|
123
|
-
end
|
132
|
+
# Instead of:
|
133
|
+
response.body.should have_node(:foo)
|
124
134
|
```
|
125
135
|
|
126
|
-
|
136
|
+
### Have JSON Node Matcher
|
127
137
|
|
128
138
|
```ruby
|
129
|
-
|
139
|
+
'{ "transaction": { "id": 54, "status": "paid" } }'.should have_json_node(:id).with(54)
|
130
140
|
```
|
131
141
|
|
132
|
-
### Have
|
142
|
+
### Have XML Node Matcher
|
133
143
|
|
134
144
|
```ruby
|
135
|
-
|
145
|
+
"<product><name>gateway</name></product>".should have_xml_node(:name).with('gateway')
|
136
146
|
```
|
137
147
|
|
138
|
-
### Have
|
148
|
+
### Have JSON Matcher
|
149
|
+
|
150
|
+
Sometimes, you want to compare the entire JSON structure:
|
139
151
|
|
140
152
|
```ruby
|
141
|
-
|
153
|
+
"['Foo', 'Bar', 'Baz']".should have_json(['Foo', 'Bar', 'Baz'])
|
142
154
|
```
|
143
155
|
|
144
156
|
### Create Resource Matcher
|
@@ -146,7 +158,7 @@ Then you can use *without* call the **#body** method:
|
|
146
158
|
This matchers see the HTTP STATUS CODE is equal to 201.
|
147
159
|
|
148
160
|
```ruby
|
149
|
-
|
161
|
+
response.status.should create_resource
|
150
162
|
```
|
151
163
|
|
152
164
|
### BAD REQUEST Matcher
|
@@ -154,8 +166,8 @@ This matchers see the HTTP STATUS CODE is equal to 201.
|
|
154
166
|
This BAD REQUEST is a matcher that see if the HTTP STATUS code is equal to 400.
|
155
167
|
|
156
168
|
```ruby
|
157
|
-
|
158
|
-
|
169
|
+
response.status.should be_a_bad_request
|
170
|
+
response.status.should be_bad_request
|
159
171
|
```
|
160
172
|
|
161
173
|
### UNAUTHORIZED Matcher
|
@@ -163,8 +175,8 @@ This BAD REQUEST is a matcher that see if the HTTP STATUS code is equal to 400.
|
|
163
175
|
This UNAUTHORIZED is a matcher that see if the HTTP STATUS code is equal to 401.
|
164
176
|
|
165
177
|
```ruby
|
166
|
-
|
167
|
-
|
178
|
+
response.status.should be_unauthorized
|
179
|
+
response.body.should have_node(:message).with('Invalid Credentials')
|
168
180
|
```
|
169
181
|
|
170
182
|
### INTERNAL SERVER ERROR Matcher
|
@@ -172,8 +184,8 @@ This UNAUTHORIZED is a matcher that see if the HTTP STATUS code is equal to 401.
|
|
172
184
|
This INTERNAL SERVER Error is a matcher that see if the HTTP STATUS code is equal to 500.
|
173
185
|
|
174
186
|
```ruby
|
175
|
-
|
176
|
-
|
187
|
+
response.status.should be_internal_server_error
|
188
|
+
response.body.should have_node(:message).with('An Internal Error Occurs in our precious app. :S')
|
177
189
|
```
|
178
190
|
|
179
191
|
### HTTP STATUS CODE Configuration
|
@@ -181,32 +193,32 @@ This INTERNAL SERVER Error is a matcher that see if the HTTP STATUS code is equa
|
|
181
193
|
You can configure the name method to call the http status code:
|
182
194
|
|
183
195
|
```ruby
|
184
|
-
|
185
|
-
|
186
|
-
|
196
|
+
APIMatchers.setup do |config|
|
197
|
+
config.http_status_method = :status
|
198
|
+
end
|
187
199
|
```
|
188
200
|
|
189
201
|
Then you can use without call the **#status** method:
|
190
202
|
|
191
203
|
```ruby
|
192
|
-
|
204
|
+
response.should create_resource
|
193
205
|
```
|
194
206
|
|
195
207
|
This configurations affects this matchers:
|
196
208
|
|
197
|
-
* be_ok
|
198
|
-
* create_resource
|
199
|
-
* be_a_bad_request
|
200
|
-
* be_internal_server_error
|
201
|
-
* be_unauthorized
|
202
|
-
* be_not_found
|
209
|
+
* `be_ok`
|
210
|
+
* `create_resource`
|
211
|
+
* `be_a_bad_request`
|
212
|
+
* `be_internal_server_error`
|
213
|
+
* `be_unauthorized`
|
214
|
+
* `be_not_found`
|
203
215
|
|
204
216
|
### Be in XML Matcher
|
205
217
|
|
206
218
|
This is a matcher that see if the content type is xml:
|
207
219
|
|
208
220
|
```ruby
|
209
|
-
|
221
|
+
response.headers['Content-Type'].should be_in_xml
|
210
222
|
```
|
211
223
|
|
212
224
|
### Be in JSON Matcher
|
@@ -214,7 +226,7 @@ This is a matcher that see if the content type is xml:
|
|
214
226
|
This is a matcher that see if the content type is in JSON:
|
215
227
|
|
216
228
|
```ruby
|
217
|
-
|
229
|
+
response.headers['Content-Type'].should be_in_json
|
218
230
|
```
|
219
231
|
|
220
232
|
### Headers Configuration
|
@@ -222,17 +234,17 @@ This is a matcher that see if the content type is in JSON:
|
|
222
234
|
You can configure the name method to call the headers and content type:
|
223
235
|
|
224
236
|
```ruby
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
237
|
+
APIMatchers.setup do |config|
|
238
|
+
config.header_method = :headers
|
239
|
+
config.header_content_type_key = 'Content-Type'
|
240
|
+
end
|
229
241
|
```
|
230
242
|
|
231
|
-
|
243
|
+
And then you will be able to use without call the **#headers** calling the **#['Content-Type']** method:
|
232
244
|
|
233
245
|
```ruby
|
234
|
-
|
235
|
-
|
246
|
+
response.should be_in_json
|
247
|
+
response.should be_in_xml
|
236
248
|
```
|
237
249
|
|
238
250
|
### Acknowlegments
|
@@ -242,3 +254,4 @@ Then you can use without call the **#headers** calling the **#['Content-Type']**
|
|
242
254
|
### Contributors
|
243
255
|
|
244
256
|
* Stephen Orens
|
257
|
+
* Lucas Caton
|
@@ -4,17 +4,26 @@ module APIMatchers
|
|
4
4
|
module ResponseBody
|
5
5
|
class HaveXmlNode < Base
|
6
6
|
def matches?(actual)
|
7
|
+
value = false
|
7
8
|
@actual = actual
|
8
9
|
xml = Nokogiri::XML(response_body)
|
9
|
-
node = xml.xpath("//#{@expected_node}").text
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
node_set = xml.xpath("//#{@expected_node}")
|
12
|
+
if node_set
|
13
|
+
node_set.each do |node|
|
14
|
+
if @with_value
|
15
|
+
value = (node.text == @with_value.to_s)
|
16
|
+
elsif @expected_including_text
|
17
|
+
value = (node.text.to_s.include?(@expected_including_text))
|
18
|
+
else
|
19
|
+
value = node.text.present?
|
20
|
+
end
|
21
|
+
# if value is true, time to return
|
22
|
+
return value if value
|
23
|
+
end
|
17
24
|
end
|
25
|
+
# at this point, it failed to match
|
26
|
+
return value
|
18
27
|
end
|
19
28
|
end
|
20
29
|
end
|
data/lib/api_matchers/version.rb
CHANGED
@@ -6,6 +6,10 @@ describe APIMatchers::ResponseBody::HaveJson do
|
|
6
6
|
it 'equal json' do
|
7
7
|
['Petshop', 'Dogs'].to_json.should have_json(['Petshop', 'Dogs'])
|
8
8
|
end
|
9
|
+
|
10
|
+
it 'compares with Hash too' do
|
11
|
+
{ 'offers' => [10, 90] }.to_json.should have_json({ 'offers' => [10,90] })
|
12
|
+
end
|
9
13
|
end
|
10
14
|
|
11
15
|
context 'when fails' do
|
@@ -63,6 +63,33 @@ describe APIMatchers::ResponseBody::HaveXmlNode do
|
|
63
63
|
}.to fail_with(%Q{expected to have node called: 'message' including text: 'Fox on the run'. Got: '<error><message>Transaction error: Name can't be blank</message></error>'})
|
64
64
|
end
|
65
65
|
end
|
66
|
+
|
67
|
+
context "find matching node when multiple records" do
|
68
|
+
it "should pass when the expected is included in the actual (1 level)" do
|
69
|
+
%{<messages>
|
70
|
+
<message><id>4</id></message>
|
71
|
+
<message><id>2</id></message>
|
72
|
+
</messages>}.should have_xml_node(:id).with(2)
|
73
|
+
end
|
74
|
+
it "should fail when the expected is not included in the actual (1 level)" do
|
75
|
+
%{<messages>
|
76
|
+
<message><id>4</id></message>
|
77
|
+
<message><id>2</id></message>
|
78
|
+
</messages>}.should_not have_xml_node(:id).with(3)
|
79
|
+
end
|
80
|
+
it "should pass when the expected is included in the actual (2 levels)" do
|
81
|
+
%{<messages>
|
82
|
+
<message><header><id>4</id></header></message>
|
83
|
+
<message><header><id>2</id></header></message>
|
84
|
+
</messages>}.should have_xml_node(:id).with(2)
|
85
|
+
end
|
86
|
+
it "should fail when the expected is not included in the actual (2 levels)" do
|
87
|
+
%{<messages>
|
88
|
+
<message><header><id>4</id></header></message>
|
89
|
+
<message><header><id>2</id></header></message>
|
90
|
+
</messages>}.should_not have_xml_node(:id).with(3)
|
91
|
+
end
|
92
|
+
end
|
66
93
|
end
|
67
94
|
|
68
95
|
describe "actual.should_not have_xml_node" do
|
metadata
CHANGED
@@ -1,55 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api_matchers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomas D'Stefano
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 2.10.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 2.10.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 3.2.5
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 3.2.5
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: nokogiri
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 1.5.2
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 1.5.2
|
55
55
|
description: Collection of RSpec matchers for create your API.
|
@@ -61,6 +61,7 @@ extra_rdoc_files: []
|
|
61
61
|
files:
|
62
62
|
- .gitignore
|
63
63
|
- .rvmrc.example
|
64
|
+
- .travis.yml
|
64
65
|
- Gemfile
|
65
66
|
- History.markdown
|
66
67
|
- LICENSE
|
@@ -117,17 +118,17 @@ require_paths:
|
|
117
118
|
- lib
|
118
119
|
required_ruby_version: !ruby/object:Gem::Requirement
|
119
120
|
requirements:
|
120
|
-
- -
|
121
|
+
- - '>='
|
121
122
|
- !ruby/object:Gem::Version
|
122
123
|
version: '0'
|
123
124
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
125
|
requirements:
|
125
|
-
- -
|
126
|
+
- - '>='
|
126
127
|
- !ruby/object:Gem::Version
|
127
128
|
version: '0'
|
128
129
|
requirements: []
|
129
130
|
rubyforge_project:
|
130
|
-
rubygems_version: 2.
|
131
|
+
rubygems_version: 2.1.10
|
131
132
|
signing_key:
|
132
133
|
specification_version: 4
|
133
134
|
summary: Collection of RSpec matchers for create your API.
|