├── .gitignore
├── .rspec
├── .rvmrc.example
├── .travis.yml
├── Gemfile
├── Gemfile.lock
├── History.markdown
├── LICENSE
├── README.markdown
├── Rakefile
├── TODO.markdown
├── api_matchers.gemspec
├── lib
├── api_matchers.rb
└── api_matchers
│ ├── core
│ ├── exceptions.rb
│ ├── find_in_json.rb
│ ├── parser.rb
│ ├── rspec_matchers.rb
│ └── setup.rb
│ ├── headers
│ ├── base.rb
│ ├── be_json.rb
│ └── be_xml.rb
│ ├── http_status_code
│ ├── base.rb
│ ├── be_bad_request.rb
│ ├── be_forbidden.rb
│ ├── be_internal_server_error.rb
│ ├── be_not_found.rb
│ ├── be_ok.rb
│ ├── be_unauthorized.rb
│ ├── be_unprocessable_entity.rb
│ └── create_resource.rb
│ ├── response_body
│ ├── base.rb
│ ├── have_json.rb
│ ├── have_json_node.rb
│ ├── have_node.rb
│ └── have_xml_node.rb
│ └── version.rb
└── spec
├── api_matchers
├── core
│ ├── find_in_json_spec.rb
│ └── setup_spec.rb
├── headers
│ ├── base_spec.rb
│ ├── be_json_spec.rb
│ └── be_xml_spec.rb
├── http_status_code
│ ├── base_spec.rb
│ ├── be_bad_request_spec.rb
│ ├── be_forbidden_spec.rb
│ ├── be_internal_server_error_spec.rb
│ ├── be_not_found_spec.rb
│ ├── be_ok_spec.rb
│ ├── be_unauthorized_spec.rb
│ ├── be_unprocessable_entity_spec.rb
│ └── create_resource_spec.rb
└── response_body
│ ├── base_spec.rb
│ ├── have_json_node_spec.rb
│ ├── have_json_spec.rb
│ ├── have_node_spec.rb
│ └── have_xml_node_spec.rb
└── spec_helper.rb
/.gitignore:
--------------------------------------------------------------------------------
1 | *.gem
2 | *.rbc
3 | .bundle
4 | .config
5 | .yardoc
6 | InstalledFiles
7 | _yardoc
8 | coverage
9 | doc/
10 | lib/bundler/man
11 | pkg
12 | rdoc
13 | spec/reports
14 | test/tmp
15 | test/version_tmp
16 | tmp
17 | *.DS_Store
18 | .rvmrc
19 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
--------------------------------------------------------------------------------
/.rvmrc.example:
--------------------------------------------------------------------------------
1 | rvm 1.9.2@api_matchers --create
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | script:
3 | - bundle exec rspec spec
4 | rvm:
5 | - rbx-2
6 | - jruby-head
7 | - ruby-head
8 | - ruby
9 | - jruby
10 | - 2.1.2
11 | - 2.0.0
12 | - 1.9.3
13 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'http://rubygems.org'
2 |
3 | # Specify your gem's dependencies in api_matchers.gemspec
4 | gemspec
5 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | api_matchers (0.6.2)
5 | activesupport (>= 3.2.5)
6 | nokogiri (~> 1.6.6.4)
7 | rspec (>= 3.1)
8 |
9 | GEM
10 | remote: http://rubygems.org/
11 | specs:
12 | activesupport (4.2.2)
13 | i18n (~> 0.7)
14 | json (~> 1.7, >= 1.7.7)
15 | minitest (~> 5.1)
16 | thread_safe (~> 0.3, >= 0.3.4)
17 | tzinfo (~> 1.1)
18 | diff-lcs (1.2.5)
19 | i18n (0.7.0)
20 | json (1.8.3)
21 | mini_portile (0.6.2)
22 | minitest (5.7.0)
23 | nokogiri (1.6.6.4)
24 | mini_portile (~> 0.6.0)
25 | rspec (3.3.0)
26 | rspec-core (~> 3.3.0)
27 | rspec-expectations (~> 3.3.0)
28 | rspec-mocks (~> 3.3.0)
29 | rspec-core (3.3.0)
30 | rspec-support (~> 3.3.0)
31 | rspec-expectations (3.3.0)
32 | diff-lcs (>= 1.2.0, < 2.0)
33 | rspec-support (~> 3.3.0)
34 | rspec-mocks (3.3.0)
35 | diff-lcs (>= 1.2.0, < 2.0)
36 | rspec-support (~> 3.3.0)
37 | rspec-support (3.3.0)
38 | thread_safe (0.3.5)
39 | tzinfo (1.2.2)
40 | thread_safe (~> 0.1)
41 |
42 | PLATFORMS
43 | ruby
44 |
45 | DEPENDENCIES
46 | api_matchers!
47 |
48 | BUNDLED WITH
49 | 1.10.6
50 |
--------------------------------------------------------------------------------
/History.markdown:
--------------------------------------------------------------------------------
1 | ## 0.6.2
2 |
3 | * Added RSpec 3.2.x and 3.3.x compatibility (Lucas Caton)
4 |
5 | ## 0.6.1
6 |
7 | * Add description to matchers. This makes RSpec not complain about missing
8 | description.
9 |
10 | ## 0.6.0
11 |
12 | * Add be_forbidden matcher:
13 |
14 | ```ruby
15 | expect(response.status).to be_forbidden
16 | ```
17 |
18 | * Add RSpec 3 and RSpec 2 compatibility.
19 |
20 | ## 0.5.1
21 |
22 | * Fix #have_json matcher fail message. Fix issue #20
23 |
24 | ## 0.5.0
25 |
26 | * Internals - Migrate to the RSpec expect syntax.
27 |
28 | ## v0.4.0
29 |
30 | * jRuby support;
31 | * have_json matcher;
32 |
33 | ## v0.1.1
34 |
35 | 1) Support Datetime, Date and Time comparison (Thanks to Stephen Orens).
36 | 2) The have_node should accept boolean values (Thanks to Stephen Orens).
37 |
38 | ## v0.1.0
39 |
40 | 1) Add the #including_text for have_json_node and have_xml_node matcher:
41 |
42 | { :error => "Transaction error: Name can't be blank" }.to_json.should have_json_node(:error).including_text("Transaction error")
43 |
44 | "Transaction error: Name can't be blank".should have_xml_node(:error).including_text("Transaction error")
45 |
46 | ## v0.0.2
47 |
48 | 1) Put the headers method and the content type key in the setup class and that will be used by the headers matchers(be_json and be_xml).
49 |
50 | This:
51 |
52 | response.headers['Content-Type'].should be_in_json
53 | response.headers['Content-Type'].should be_in_xml
54 |
55 | With:
56 |
57 | APIMatchers.setup do |config|
58 | config.header_method = :headers
59 | config.header_content_type_key = 'Content-Type'
60 | end
61 |
62 | Becomes:
63 |
64 | response.should be_in_json
65 | response.should be_in_xml
66 |
67 | ## v0.0.1
68 |
69 | 1) Headers Matchers: be_xml, be_json (**OBS:** Need to think about the setup!)
70 | 2) HTTP Status Matchers: be_a_bad_request, be_internal_server_error, be_unauthorized, create_resource
71 | 3) Response body Matchers: have_node, have_json_node, have_xml_node
72 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012-2013 Tomas D'Stefano
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | # API Matchers [](https://travis-ci.org/tomas-stefano/api_matchers)
2 |
3 | Collection of RSpec matchers for your API.
4 |
5 | ## Response Body Matchers
6 |
7 | * `have_node`
8 | * `have_json_node`
9 | * `have_xml_node`
10 | * `have_json`
11 |
12 | ## Response Status Matchers
13 |
14 | * `be_ok`
15 | * `create_resource`
16 | * `be_a_bad_request`
17 | * `be_unauthorized`
18 | * `be_forbidden`
19 | * `be_internal_server_error`
20 | * `be_not_found`
21 |
22 | ## Other Matchers
23 |
24 | * `be_in_xml`
25 | * `be_in_json`
26 |
27 | ## Install
28 |
29 | Include the gem to your test group in you Gemfile:
30 |
31 | ```ruby
32 | group :test do
33 | gem 'api_matchers'
34 | # other gems
35 | end
36 | ```
37 |
38 | Or install it manually: `gem install api_matchers`.
39 |
40 | ## Usage
41 |
42 | ### Including in RSpec
43 |
44 | To include all this matchers you need to include the APIMatchers::RSpecMatchers module:
45 |
46 | ```ruby
47 | RSpec.configure do |config|
48 | config.include APIMatchers::RSpecMatchers
49 | end
50 | ```
51 |
52 | ### Have Node Matcher
53 |
54 | The have_node matcher parse the actual and see if have the expcted node with the expected value.
55 | **The default that have_node will parse is JSON.**
56 |
57 | You can verify if node exists:
58 |
59 | ```ruby
60 | expect('{ "transaction": { "id": 54, "status": "paid" } }').to have_node(:transaction)
61 | ```
62 |
63 | Or if node exist with a value:
64 |
65 | ```ruby
66 | expect('{ "transaction": { "id": 54, "status": "paid" } }').to have_node(:id).with(54)
67 | ```
68 |
69 | ```ruby
70 | expect('{ "error": "not_authorized" }').to have_node(:error).with('not_authorized')
71 | ```
72 |
73 | ```ruby
74 | expect('{"parcels":1 }').to have_node(:parcels).with(1)
75 | ```
76 |
77 | To see the json node and see if include a text, you can do this:
78 |
79 | ```ruby
80 | expect('{"error": "Transaction error: Name cant be blank"}').to have_node(:error).including_text("Transaction error")
81 | ```
82 |
83 | You can verify boolean values too:
84 |
85 | ```ruby
86 | expect('{"creditcard":true}').to have_node(:creditcard).with(true)
87 | ```
88 |
89 | ### HAVE NODE Matcher Configuration
90 |
91 | You can configure if you want xml (JSON is the default):
92 |
93 | ```ruby
94 | APIMatchers.setup do |config|
95 | config.content_type = :xml
96 | end
97 | ```
98 |
99 | ```ruby
100 | expect('200paid').to have_node(:status)
101 | ```
102 |
103 | Using the `with` method:
104 |
105 | ```ruby
106 | expect('200paid').to have_node(:status).with('paid')
107 | ```
108 |
109 | Or you can use the `have_xml_node` matcher:
110 |
111 | ```ruby
112 | expect(
113 | "Transaction error: Name can't be blank"
114 | ).to have_xml_node(:error).with("Transaction error: Name can't be blank")
115 | ```
116 |
117 | To see the xml node and see if include a text, you can do this:
118 |
119 | ```ruby
120 | expect(
121 | "Transaction error: Name can't be blank"
122 | ).to have_xml_node(:error).including_text("Transaction error")
123 | ```
124 |
125 | **If you work with xml and json in the same API, check the have_json_node and have_xml_node matchers.**
126 |
127 | You can configure the name of the method and then you will be able to use *without* the **#body** method, for example:
128 |
129 | ```ruby
130 | APIMatchers.setup do |config|
131 | config.response_body_method = :body
132 | end
133 |
134 | expect(response).to have_node(:foo).with('bar')
135 | ```
136 |
137 | Instead of:
138 |
139 | ```ruby
140 | expect(response.body).to have_node(:foo)
141 | ```
142 |
143 | ### Have JSON Node Matcher
144 |
145 | ```ruby
146 | expect(
147 | '{ "transaction": { "id": 54, "status": "paid" } }'
148 | ).to have_json_node(:id).with(54)
149 | ```
150 |
151 | ### Have XML Node Matcher
152 |
153 | ```ruby
154 | expect("gateway").to have_xml_node(:name).with('gateway')
155 | ```
156 |
157 | ### Have JSON Matcher
158 |
159 | Sometimes, you want to compare the entire JSON structure:
160 |
161 | ```ruby
162 | expect("['Foo', 'Bar', 'Baz']").to have_json(['Foo', 'Bar', 'Baz'])
163 | ```
164 |
165 | ### Create Resource Matcher
166 |
167 | This matchers see the HTTP STATUS CODE is equal to 201.
168 |
169 | ```ruby
170 | expect(response.status).to create_resource
171 | ```
172 |
173 | ### BAD REQUEST Matcher
174 |
175 | This BAD REQUEST is a matcher that see if the HTTP STATUS code is equal to 400.
176 |
177 | ```ruby
178 | expect(response.status).to be_a_bad_request
179 | expect(response.status).to be_bad_request
180 | ```
181 |
182 | ### UNAUTHORIZED Matcher
183 |
184 | This UNAUTHORIZED is a matcher that see if the HTTP STATUS code is equal to 401.
185 |
186 | ```ruby
187 | expect(response.status).to be_unauthorized
188 | expect(response.body).to have_node(:message).with('Invalid Credentials')
189 | ```
190 |
191 | ### FORBIDDEN Matcher
192 |
193 | This is a matcher to see if the HTTP STATUS code is equal to 403.
194 |
195 | ```ruby
196 | expect(response.status).to be_forbidden
197 | ```
198 |
199 | ### INTERNAL SERVER ERROR Matcher
200 |
201 | This INTERNAL SERVER Error is a matcher that see if the HTTP STATUS code is equal to 500.
202 |
203 | ```ruby
204 | expect(response.status).to be_internal_server_error
205 | expect(
206 | response.body
207 | ).to have_node(:message).with('An Internal Error Occurs in our precious app. :S')
208 | ```
209 |
210 | ### HTTP STATUS CODE Configuration
211 |
212 | You can configure the name method to call the http status code:
213 |
214 | ```ruby
215 | APIMatchers.setup do |config|
216 | config.http_status_method = :status
217 | end
218 | ```
219 |
220 | Then you can use without call the **#status** method:
221 |
222 | ```ruby
223 | expect(response).to create_resource
224 | ```
225 |
226 | This configurations affects this matchers:
227 |
228 | * `be_ok`
229 | * `create_resource`
230 | * `be_a_bad_request`
231 | * `be_internal_server_error`
232 | * `be_unauthorized`
233 | * `be_forbidden`
234 | * `be_not_found`
235 |
236 | ### Be in XML Matcher
237 |
238 | This is a matcher that see if the content type is xml:
239 |
240 | ```ruby
241 | expect(response.headers['Content-Type']).to be_in_xml
242 | ```
243 |
244 | ### Be in JSON Matcher
245 |
246 | This is a matcher that see if the content type is in JSON:
247 |
248 | ```ruby
249 | expect(response.headers['Content-Type']).to be_in_json
250 | ```
251 |
252 | ### Headers Configuration
253 |
254 | You can configure the name method to call the headers and content type:
255 |
256 | ```ruby
257 | APIMatchers.setup do |config|
258 | config.header_method = :headers
259 | config.header_content_type_key = 'Content-Type'
260 | end
261 | ```
262 |
263 | And then you will be able to use without call the **#headers** calling the **#['Content-Type']** method:
264 |
265 | ```ruby
266 | expect(response).to be_in_json
267 | expect(response).to be_in_xml
268 | ```
269 |
270 | ### Acknowlegments
271 |
272 | * Special thanks to Daniel Konishi to contribute in the product that I extracted the matchers to this gem.
273 |
274 | ### Contributors
275 |
276 | * Stephen Orens
277 | * Lucas Caton
278 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env rake
2 | require "bundler/gem_tasks"
3 |
--------------------------------------------------------------------------------
/TODO.markdown:
--------------------------------------------------------------------------------
1 | * Refactor Core::FindInJSON#find method.
2 | * Improve the error messages from all matchers.
3 | * Adding some include matcher about node arrays.
4 |
--------------------------------------------------------------------------------
/api_matchers.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | require File.expand_path('../lib/api_matchers/version', __FILE__)
3 |
4 | Gem::Specification.new do |gem|
5 | gem.authors = ["Tomas D'Stefano"]
6 | gem.email = ["tomas_stefano@successoft.com"]
7 | gem.description = %q{Collection of RSpec matchers for create your API.}
8 | gem.summary = %q{Collection of RSpec matchers for create your API.}
9 | gem.homepage = "https://github.com/tomas-stefano/api_matchers"
10 |
11 | gem.files = `git ls-files`.split($\)
12 | gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13 | gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14 | gem.name = "api_matchers"
15 | gem.require_paths = ["lib"]
16 | gem.version = APIMatchers::VERSION
17 |
18 | gem.add_dependency 'rspec', '>= 3.1'
19 | gem.add_dependency 'activesupport', '>= 3.2.5'
20 | gem.add_dependency 'nokogiri', '~> 1.6.6.4'
21 | end
22 |
--------------------------------------------------------------------------------
/lib/api_matchers.rb:
--------------------------------------------------------------------------------
1 | require "api_matchers/version"
2 | require "active_support/core_ext/object"
3 | require "active_support/core_ext/class"
4 |
5 | module APIMatchers
6 | autoload :RSpecMatchers, 'api_matchers/core/rspec_matchers'
7 |
8 | # HTTP Status Code Matchers
9 | #
10 | module HTTPStatusCode
11 | autoload :Base, 'api_matchers/http_status_code/base'
12 | autoload :BeBadRequest, 'api_matchers/http_status_code/be_bad_request'
13 | autoload :BeNotFound, 'api_matchers/http_status_code/be_not_found'
14 | autoload :BeInternalServerError, 'api_matchers/http_status_code/be_internal_server_error'
15 | autoload :BeUnauthorized, 'api_matchers/http_status_code/be_unauthorized'
16 | autoload :BeOk, 'api_matchers/http_status_code/be_ok'
17 | autoload :BeUnprocessableEntity, 'api_matchers/http_status_code/be_unprocessable_entity'
18 | autoload :BeForbidden, 'api_matchers/http_status_code/be_forbidden'
19 | autoload :CreateResource, 'api_matchers/http_status_code/create_resource'
20 | end
21 |
22 | # Content Type Matchers
23 | #
24 | module Headers
25 | autoload :Base, 'api_matchers/headers/base'
26 | autoload :BeXML, 'api_matchers/headers/be_xml'
27 | autoload :BeJSON, 'api_matchers/headers/be_json'
28 | end
29 |
30 | # Response Body Matchers
31 | #
32 | module ResponseBody
33 | autoload :Base, 'api_matchers/response_body/base'
34 | autoload :HaveJsonNode, 'api_matchers/response_body/have_json_node'
35 | autoload :HaveJson, 'api_matchers/response_body/have_json'
36 | autoload :HaveXmlNode, 'api_matchers/response_body/have_xml_node'
37 | autoload :HaveNode, 'api_matchers/response_body/have_node'
38 | end
39 |
40 | # Core
41 | #
42 | module Core
43 | autoload :FindInJSON, 'api_matchers/core/find_in_json'
44 | autoload :Parser, 'api_matchers/core/parser'
45 | autoload :Setup, 'api_matchers/core/setup'
46 | autoload :Exceptions, 'api_matchers/core/exceptions'
47 | end
48 | include ::APIMatchers::Core::Exceptions
49 |
50 | def self.setup
51 | yield(::APIMatchers::Core::Setup)
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/lib/api_matchers/core/exceptions.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module Core
3 | module Exceptions
4 | class KeyNotFound < StandardError
5 | end
6 |
7 | class InvalidJSON < StandardError
8 | end
9 | end
10 | end
11 | end
--------------------------------------------------------------------------------
/lib/api_matchers/core/find_in_json.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module Core
3 | class FindInJSON
4 | attr_reader :json
5 |
6 | def initialize(json)
7 | @json = json
8 | end
9 |
10 | def find(options={})
11 | expected_key = options.fetch(:node).to_s
12 | expected_value = options[:value]
13 |
14 | @json.each do |key, value|
15 | if key == expected_key
16 | unless expected_value.nil?
17 | if expected_value.is_a? DateTime or expected_value.is_a? Date
18 | expected_value = expected_value.to_s
19 | elsif expected_value.is_a? Time
20 | expected_value = expected_value.to_datetime.to_s
21 | end
22 | end
23 | return value if value == expected_value or expected_value.nil?
24 | end
25 |
26 | # do we have more to recurse through?
27 | keep_going = nil
28 | if value.is_a? Hash or value.is_a? Array
29 | keep_going = value # hash or array, keep going
30 | elsif value.nil? and key.is_a? Hash
31 | keep_going = key # the array was passed in and now in the key, keep going
32 | end
33 |
34 | if keep_going
35 | begin
36 | # ignore nodes where the key doesn't match
37 | return FindInJSON.new(keep_going).find(node: expected_key, value: expected_value)
38 | rescue ::APIMatchers::Core::Exceptions::KeyNotFound
39 | end
40 | end
41 |
42 | end
43 | # we did not find the requested key
44 | raise ::APIMatchers::Core::Exceptions::KeyNotFound.new("key was not found")
45 | end
46 | end
47 | end
48 | end
--------------------------------------------------------------------------------
/lib/api_matchers/core/parser.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module Core
3 | module Parser
4 | def json
5 | JSON.parse(response_body)
6 | rescue JSON::ParserError => exception
7 | raise ::APIMatchers::InvalidJSON.new("Invalid JSON: '#{response_body}'")
8 | end
9 | end
10 | end
11 | end
--------------------------------------------------------------------------------
/lib/api_matchers/core/rspec_matchers.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module RSpecMatchers
3 | def be_bad_request
4 | ::APIMatchers::HTTPStatusCode::BeBadRequest.new(::APIMatchers::Core::Setup)
5 | end
6 | alias :be_a_bad_request :be_bad_request
7 |
8 | def be_not_found
9 | ::APIMatchers::HTTPStatusCode::BeNotFound.new(::APIMatchers::Core::Setup)
10 | end
11 |
12 | def be_internal_server_error
13 | ::APIMatchers::HTTPStatusCode::BeInternalServerError.new(::APIMatchers::Core::Setup)
14 | end
15 | alias :be_an_internal_server_error :be_internal_server_error
16 |
17 | def be_unauthorized
18 | ::APIMatchers::HTTPStatusCode::BeUnauthorized.new(::APIMatchers::Core::Setup)
19 | end
20 |
21 | def be_forbidden
22 | ::APIMatchers::HTTPStatusCode::BeForbidden.new(::APIMatchers::Core::Setup)
23 | end
24 |
25 | def be_ok
26 | ::APIMatchers::HTTPStatusCode::BeOk.new(::APIMatchers::Core::Setup)
27 | end
28 |
29 | def be_unprocessable_entity
30 | ::APIMatchers::HTTPStatusCode::BeUnprocessableEntity.new(::APIMatchers::Core::Setup)
31 | end
32 |
33 | def create_resource
34 | ::APIMatchers::HTTPStatusCode::CreateResource.new(::APIMatchers::Core::Setup)
35 | end
36 | alias :created_resource :create_resource
37 |
38 | def be_xml
39 | ::APIMatchers::Headers::BeXML.new(::APIMatchers::Core::Setup)
40 | end
41 | alias :be_in_xml :be_xml
42 |
43 | def be_json
44 | ::APIMatchers::Headers::BeJSON.new(::APIMatchers::Core::Setup)
45 | end
46 | alias :be_in_json :be_json
47 | alias :be_a_json :be_json
48 |
49 | def have_json_node(expected_node)
50 | ::APIMatchers::ResponseBody::HaveJsonNode.new(expected_node: expected_node, setup: ::APIMatchers::Core::Setup)
51 | end
52 |
53 | def have_xml_node(expected_node)
54 | ::APIMatchers::ResponseBody::HaveXmlNode.new(expected_node: expected_node, setup: ::APIMatchers::Core::Setup)
55 | end
56 |
57 | def have_json(expected_json)
58 | ::APIMatchers::ResponseBody::HaveJson.new(expected_json)
59 | end
60 |
61 | def have_node(expected_node)
62 | if ::APIMatchers::Core::Setup.have_node_matcher.equal?(:json)
63 | have_json_node(expected_node)
64 | else
65 | have_xml_node(expected_node)
66 | end
67 | end
68 | end
69 | end
--------------------------------------------------------------------------------
/lib/api_matchers/core/setup.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module Core
3 | class Setup
4 | # The http status method that will be called when you call http status matchers
5 | #
6 | # ==== Examples
7 | #
8 | # response.status.should create_resource
9 | # response.status.should be_bad_request
10 | # response.status.should be_unauthorized
11 | #
12 | # # Instead calling #status everytime, you can configure:
13 | #
14 | # APIMatchers.setup do |config|
15 | # config.http_status_method = :status
16 | # end
17 | #
18 | # Then:
19 | #
20 | # response.should create_resource
21 | # response.should be_bad_request
22 | # response.should be_unauthorized
23 | #
24 | cattr_accessor :http_status_method
25 |
26 | # The response body method that will be called when you call the have_node matchers
27 | #
28 | # ==== Examples
29 | #
30 | # response.body.should have_node(:foo)
31 | # response.body.should have_node(:bar)
32 | # response.body.should have_node(:baz)
33 | #
34 | # # Instead calling #body everytime, you can configure:
35 | #
36 | # APIMatchers.setup do |config|
37 | # config.http_status_method = :body
38 | # end
39 | #
40 | # Then:
41 | #
42 | # response.should have_node(:foo)
43 | # response.should have_node(:bar)
44 | # response.should have_node(:baz)
45 | #
46 | cattr_accessor :response_body_method
47 |
48 | # The default have node matcher that will be used.
49 | # This have_node matcher is useful when you just work with one content type in your API.
50 | # Change to :xml if you want that have_node works ONLY with XML.
51 | # If you work with xml and json in the same API, I recommend that you check the
52 | # have_json_node and have_xml_node matchers.
53 | #
54 | cattr_accessor :have_node_matcher
55 | self.have_node_matcher = :json
56 |
57 | # The headers method and the content type key that will be used by the headers matchers.
58 | #
59 | # ==== Examples
60 | #
61 | # response.response_header['Content-Type'].should be_json
62 | # response.response_header['Content-Type'].should be_xml
63 | #
64 | # # Instead calling #response_header everytime, you can configure:
65 | #
66 | # APIMatchers.setup do |config|
67 | # config.header_method = :response_header
68 | # config.header_content_type_key = 'Content-Type'
69 | # end
70 | #
71 | # Then:
72 | #
73 | # response.should be_json
74 | # response.should be_xml
75 | #
76 | cattr_accessor :header_method
77 | cattr_accessor :header_content_type_key
78 | end
79 | end
80 | end
--------------------------------------------------------------------------------
/lib/api_matchers/headers/base.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module Headers
3 | class Base
4 | attr_reader :setup
5 |
6 | def initialize(setup)
7 | @setup = setup
8 | end
9 |
10 | def matches?(actual)
11 | @actual = actual
12 |
13 | content_type_response.eql?(expected_content_type)
14 | end
15 |
16 | def content_type_response
17 | if @setup.header_method.present? and @setup.header_content_type_key.present?
18 | headers = @actual.send(@setup.header_method)
19 | headers[@setup.header_content_type_key] || headers if headers.present?
20 | else
21 | @actual
22 | end
23 | end
24 |
25 | def expected_content_type
26 | raise NotImplementedError, "not implemented on #{self}"
27 | end
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/lib/api_matchers/headers/be_json.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module Headers
3 | class BeJSON < Base
4 | def expected_content_type
5 | 'application/json; charset=utf-8'
6 | end
7 |
8 | def failure_message
9 | %Q{expected a JSON response with '#{expected_content_type}'. Got: '#{content_type_response}'.}
10 | end
11 |
12 | def failure_message_when_negated
13 | %Q{expected to not be a JSON response. Got: '#{expected_content_type}'.}
14 | end
15 |
16 | def description
17 | "be in JSON"
18 | end
19 |
20 | # RSpec 2 compatibility:
21 | alias_method :failure_message_for_should, :failure_message
22 | alias_method :failure_message_for_should_not, :failure_message_when_negated
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/api_matchers/headers/be_xml.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module Headers
3 | class BeXML < Base
4 | def expected_content_type
5 | 'application/xml; charset=utf-8'
6 | end
7 |
8 | def failure_message
9 | %Q{expected a XML response with '#{expected_content_type}'. Got: '#{content_type_response}'.}
10 | end
11 |
12 | def failure_message_when_negated
13 | %Q{expected to not be a XML response. Got: '#{expected_content_type}'.}
14 | end
15 |
16 | def description
17 | "be in XML"
18 | end
19 |
20 | # RSpec 2 compatibility:
21 | alias_method :failure_message_for_should, :failure_message
22 | alias_method :failure_message_for_should_not, :failure_message_when_negated
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/api_matchers/http_status_code/base.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module HTTPStatusCode
3 | class Base
4 | attr_reader :setup
5 |
6 | def initialize(setup)
7 | @setup = setup
8 | end
9 |
10 | # Matches the actual with the expected http status code
11 | #
12 | def matches?(actual)
13 | @http_status_code = find_http_status_code(actual)
14 | @http_status_code.equal?(expected_status_code)
15 | end
16 |
17 | def expected_status_code
18 | raise NotImplementedError, "not implemented on #{self}"
19 | end
20 |
21 | # If have some configuration about the method to call on actual that method will be called.
22 | #
23 | def find_http_status_code(actual)
24 | if @setup.http_status_method.present?
25 | actual.send(@setup.http_status_method)
26 | else
27 | actual
28 | end
29 | end
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/lib/api_matchers/http_status_code/be_bad_request.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module HTTPStatusCode
3 | class BeBadRequest < Base
4 | def expected_status_code
5 | 400
6 | end
7 |
8 | def failure_message
9 | %Q{expected that '#{@http_status_code}' to be a Bad Request with the status '400'.}
10 | end
11 |
12 | def failure_message_when_negated
13 | %Q{expected that '#{@http_status_code}' to NOT be a Bad Request with the status '400'.}
14 | end
15 |
16 | def description
17 | "be a Bad Request with the status '400'"
18 | end
19 |
20 | # RSpec 2 compatibility:
21 | alias_method :failure_message_for_should, :failure_message
22 | alias_method :failure_message_for_should_not, :failure_message_when_negated
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/api_matchers/http_status_code/be_forbidden.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module HTTPStatusCode
3 | class BeForbidden < Base
4 | def expected_status_code
5 | 403
6 | end
7 |
8 | def failure_message
9 | %Q{expected that '#{@http_status_code}' to be Forbidden with the status '403'.}
10 | end
11 |
12 | def failure_message_when_negated
13 | %Q{expected that '#{@http_status_code}' to NOT be Forbidden.}
14 | end
15 |
16 | # RSpec 2 compatibility:
17 | alias_method :failure_message_for_should, :failure_message
18 | alias_method :failure_message_for_should_not, :failure_message_when_negated
19 | end
20 | end
21 | end
--------------------------------------------------------------------------------
/lib/api_matchers/http_status_code/be_internal_server_error.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module HTTPStatusCode
3 | class BeInternalServerError < Base
4 | def expected_status_code
5 | 500
6 | end
7 |
8 | def failure_message
9 | %Q{expected that '#{@http_status_code}' to be Internal Server Error with the status '500'.}
10 | end
11 |
12 | def failure_message_when_negated
13 | %Q{expected that '#{@http_status_code}' to NOT be Internal Server Error.}
14 | end
15 |
16 | def description
17 | "be Internal Server Error with the status '500'"
18 | end
19 |
20 | # RSpec 2 compatibility:
21 | alias_method :failure_message_for_should, :failure_message
22 | alias_method :failure_message_for_should_not, :failure_message_when_negated
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/api_matchers/http_status_code/be_not_found.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module HTTPStatusCode
3 | class BeNotFound < Base
4 | def expected_status_code
5 | 404
6 | end
7 |
8 | def failure_message
9 | %Q{expected that '#{@http_status_code}' to be Not Found with the status '404'.}
10 | end
11 |
12 | def failure_message_when_negated
13 | %Q{expected that '#{@http_status_code}' to NOT be Not Found with the status '404'.}
14 | end
15 |
16 | def description
17 | "be Not Found with the status '404'"
18 | end
19 |
20 | # RSpec 2 compatibility:
21 | alias_method :failure_message_for_should, :failure_message
22 | alias_method :failure_message_for_should_not, :failure_message_when_negated
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/api_matchers/http_status_code/be_ok.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module HTTPStatusCode
3 | class BeOk < Base
4 | def expected_status_code
5 | 200
6 | end
7 |
8 | def failure_message
9 | %Q{expected that '#{@http_status_code}' to be ok with the status '200'.}
10 | end
11 |
12 | def failure_message_when_negated
13 | %Q{expected that '#{@http_status_code}' to NOT be ok with the status '200'.}
14 | end
15 |
16 | def description
17 | "be ok with the status '200'"
18 | end
19 |
20 | # RSpec 2 compatibility:
21 | alias_method :failure_message_for_should, :failure_message
22 | alias_method :failure_message_for_should_not, :failure_message_when_negated
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/api_matchers/http_status_code/be_unauthorized.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module HTTPStatusCode
3 | class BeUnauthorized < Base
4 | def expected_status_code
5 | 401
6 | end
7 |
8 | def failure_message
9 | %Q{expected that '#{@http_status_code}' to be Unauthorized with the status '401'.}
10 | end
11 |
12 | def failure_message_when_negated
13 | %Q{expected that '#{@http_status_code}' to NOT be Unauthorized.}
14 | end
15 |
16 | def description
17 | "be Unauthorized with the status '401'"
18 | end
19 |
20 | # RSpec 2 compatibility:
21 | alias_method :failure_message_for_should, :failure_message
22 | alias_method :failure_message_for_should_not, :failure_message_when_negated
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/api_matchers/http_status_code/be_unprocessable_entity.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module HTTPStatusCode
3 | class BeUnprocessableEntity < Base
4 | def expected_status_code
5 | 422
6 | end
7 |
8 | def failure_message
9 | %Q{expected that '#{@http_status_code}' to be Unprocessable entity with the status '#{expected_status_code}'.}
10 | end
11 |
12 | def failure_message_when_negated
13 | %Q{expected that '#{@http_status_code}' to NOT be Unprocessable entity with the status '#{expected_status_code}'.}
14 | end
15 |
16 | def description
17 | "be Unprocessable entity with the status '422'"
18 | end
19 |
20 | # RSpec 2 compatibility:
21 | alias_method :failure_message_for_should, :failure_message
22 | alias_method :failure_message_for_should_not, :failure_message_when_negated
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/api_matchers/http_status_code/create_resource.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module HTTPStatusCode
3 | class CreateResource < Base
4 | def expected_status_code
5 | 201
6 | end
7 |
8 | def failure_message
9 | %Q{expected that '#{@http_status_code}' to be Created Resource with the status '201'.}
10 | end
11 |
12 | def failure_message_when_negated
13 | %Q{expected that '#{@http_status_code}' to NOT be Created Resource.}
14 | end
15 |
16 | def description
17 | "be Created Resource with the status '201'"
18 | end
19 |
20 | # RSpec 2 compatibility:
21 | alias_method :failure_message_for_should, :failure_message
22 | alias_method :failure_message_for_should_not, :failure_message_when_negated
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/api_matchers/response_body/base.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module ResponseBody
3 | class Base
4 | attr_reader :setup, :expected_node, :actual
5 | attr_writer :actual
6 |
7 | def initialize(options={})
8 | @expected_node = options.fetch(:expected_node)
9 | @setup = options.fetch(:setup)
10 | end
11 |
12 | def matches?(actual)
13 | raise NotImplementedError, "not implemented on #{self}"
14 | end
15 |
16 | def with(expected_value)
17 | @with_value = expected_value
18 | self
19 | end
20 |
21 | def including_text(expected_including_text)
22 | @expected_including_text = expected_including_text
23 | self
24 | end
25 |
26 | def response_body
27 | if @setup.response_body_method.present?
28 | @actual.send(@setup.response_body_method)
29 | else
30 | @actual
31 | end
32 | end
33 |
34 | def failure_message
35 | "expected to have node called: '#{@expected_node}'" << added_message << ". Got: '#{response_body}'"
36 | end
37 |
38 | def failure_message_when_negated
39 | "expected to NOT have node called: '#{@expected_node}'" << added_message << ". Got: '#{response_body}'"
40 | end
41 |
42 | # RSpec 2 compatibility:
43 | alias_method :failure_message_for_should, :failure_message
44 | alias_method :failure_message_for_should_not, :failure_message_when_negated
45 |
46 | def added_message
47 | if @with_value
48 | " with value: '#{@with_value}'"
49 | elsif @expected_including_text
50 | " including text: '#{@expected_including_text}'"
51 | else
52 | ""
53 | end
54 | end
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/lib/api_matchers/response_body/have_json.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module ResponseBody
3 | class HaveJson
4 | include APIMatchers::Core::Parser
5 | attr_reader :expected_json, :response_body
6 |
7 | def initialize(expected_json)
8 | @expected_json = expected_json
9 | end
10 |
11 | def matches?(actual)
12 | @response_body = actual
13 |
14 | @expected_json == json
15 | end
16 |
17 | def failure_message
18 | "expect to have json: '#{expected_json}'. Got: '#{json}'."
19 | end
20 |
21 | def failure_message_when_negated
22 | "expect to NOT have json: '#{response_body}'."
23 | end
24 |
25 | # RSpec 2 compatibility:
26 | alias_method :failure_message_for_should, :failure_message
27 | alias_method :failure_message_for_should_not, :failure_message_when_negated
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/lib/api_matchers/response_body/have_json_node.rb:
--------------------------------------------------------------------------------
1 | require 'json'
2 | require 'active_support/core_ext/hash'
3 |
4 | module APIMatchers
5 | module ResponseBody
6 | class HaveJsonNode < Base
7 | include APIMatchers::Core::Parser
8 |
9 | def matches?(actual)
10 | @actual = actual
11 |
12 | begin
13 | node = Core::FindInJSON.new(json).find(node: @expected_node.to_s, value: @with_value)
14 |
15 | if @expected_including_text
16 | node.to_s.include?(@expected_including_text)
17 | else
18 | true # the node is present
19 | end
20 | rescue ::APIMatchers::KeyNotFound
21 | false # the key was not found
22 | end
23 | end
24 | end
25 | end
26 | end
--------------------------------------------------------------------------------
/lib/api_matchers/response_body/have_node.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | module ResponseBody
3 | class HaveNode
4 | end
5 | end
6 | end
--------------------------------------------------------------------------------
/lib/api_matchers/response_body/have_xml_node.rb:
--------------------------------------------------------------------------------
1 | require 'nokogiri'
2 |
3 | module APIMatchers
4 | module ResponseBody
5 | class HaveXmlNode < Base
6 | def matches?(actual)
7 | value = false
8 | @actual = actual
9 | xml = Nokogiri::XML(response_body)
10 |
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
24 | end
25 | # at this point, it failed to match
26 | return value
27 | end
28 | end
29 | end
30 | end
--------------------------------------------------------------------------------
/lib/api_matchers/version.rb:
--------------------------------------------------------------------------------
1 | module APIMatchers
2 | VERSION = '0.6.2'
3 | end
4 |
--------------------------------------------------------------------------------
/spec/api_matchers/core/find_in_json_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | module APIMatchers::Core
4 | RSpec.describe FindInJSON do
5 | describe "#find" do
6 | context 'when node exists' do
7 | it "should return the value of the expected key" do
8 | expect(FindInJSON.new('product' => 'gateway').find(node: 'product')).to eql 'gateway'
9 | end
10 |
11 | it "should return the value of the deep expected key in the json" do
12 | expect(FindInJSON.new('transaction' => { 'error' => { 'code' => '999' } }).find(node: 'code')).to eql '999'
13 | end
14 | end
15 |
16 | context 'when node do not exists' do
17 | it "should return nil if don't find the expected node" do
18 | expect { FindInJSON.new('product' => 'pabx').find(node: 'developers') }.to raise_error( ::APIMatchers::Core::Exceptions::KeyNotFound)
19 | end
20 |
21 | it "should return nil if don't find the expected node in the deep JSON" do
22 | expect { FindInJSON.new('transaction' => { 'id' => 150, 'error' => {} }).find(node: 'code') }.to raise_error( ::APIMatchers::Core::Exceptions::KeyNotFound)
23 | end
24 | end
25 | end
26 | end
27 | end
--------------------------------------------------------------------------------
/spec/api_matchers/core/setup_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::Core::Setup do
4 | end
--------------------------------------------------------------------------------
/spec/api_matchers/headers/base_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::Headers::Base do
4 | let(:setup) { OpenStruct.new }
5 | subject { APIMatchers::Headers::Base.new(setup) }
6 |
7 | describe "#matches?" do
8 | it "should raise Not Implement Exception" do
9 | expect { subject.matches?('application/xml') }.to raise_error(NotImplementedError, "not implemented on #{subject}")
10 | end
11 | end
12 | end
--------------------------------------------------------------------------------
/spec/api_matchers/headers/be_json_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::Headers::BeJSON do
4 | describe "actual.to be_json" do
5 | it "should pass when the actual is json response" do
6 | expect("application/json; charset=utf-8").to be_json
7 | end
8 |
9 | it "should not pass when the actual is not a json response" do
10 | expect {
11 | expect("application/xml; charset=utf-8").to be_json
12 | }.to fail_with(%Q{expected a JSON response with 'application/json; charset=utf-8'. Got: 'application/xml; charset=utf-8'.})
13 | end
14 | end
15 |
16 | describe "actual.not_to be_json" do
17 | it "should pass when the actual is not a json response" do
18 | expect("application/xml; charset=utf-8").not_to be_json
19 | end
20 |
21 | it "should not pass when the actual is a json response" do
22 | expect{
23 | expect("application/json; charset=utf-8").not_to be_json
24 | }.to fail_with(%Q{expected to not be a JSON response. Got: 'application/json; charset=utf-8'.})
25 | end
26 | end
27 |
28 | describe "with change configuration" do
29 | before do
30 | APIMatchers.setup do |config|
31 | config.header_method = :response_header
32 | config.header_content_type_key = 'Content-Type'
33 | end
34 | end
35 |
36 | after do
37 | APIMatchers.setup do |config|
38 | config.header_method = nil
39 | config.header_content_type_key = nil
40 | end
41 | end
42 |
43 | it "should pass if the actual.response_header is equal to application/json" do
44 | response = OpenStruct.new(:response_header => { 'Content-Type' => "application/json; charset=utf-8"})
45 | expect(response).to be_json
46 | end
47 |
48 | it "should fail if the actual.response_header is not equal to application/json" do
49 | response = OpenStruct.new(:response_header => { "Content-Type" => "application/xml; charset=utf-8"})
50 | expect {
51 | expect(response).to be_json
52 | }.to fail_with(%Q{expected a JSON response with 'application/json; charset=utf-8'. Got: 'application/xml; charset=utf-8'.})
53 | end
54 |
55 | it "should fail if the actual.response_header is not equal to application/json" do
56 | response = OpenStruct.new(:response_header => { "foo-bar" => "application/xml; charset=utf-8"})
57 | expect {
58 | expect(response).to be_json
59 | }.to fail_with(%Q{expected a JSON response with 'application/json; charset=utf-8'. Got: '{"foo-bar"=>"application/xml; charset=utf-8"}'.})
60 | end
61 | end
62 | end
--------------------------------------------------------------------------------
/spec/api_matchers/headers/be_xml_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::Headers::BeXML do
4 | describe "actual.to be_xml" do
5 | it "should pass when the actual is json response" do
6 | expect("application/xml; charset=utf-8").to be_xml
7 | end
8 |
9 | it "should not pass when the actual is not a json response" do
10 | expect {
11 | expect("application/json; charset=utf-8").to be_xml
12 | }.to fail_with(%Q{expected a XML response with 'application/xml; charset=utf-8'. Got: 'application/json; charset=utf-8'.})
13 | end
14 | end
15 |
16 | describe "actual.not_to be_xml" do
17 | it "should pass when the actual is not a json response" do
18 | expect("application/json; charset=utf-8").not_to be_xml
19 | end
20 |
21 | it "should not pass when the actual is a json response" do
22 | expect {
23 | expect("application/xml; charset=utf-8").not_to be_xml
24 | }.to fail_with(%Q{expected to not be a XML response. Got: 'application/xml; charset=utf-8'.})
25 | end
26 | end
27 |
28 | describe "with change configuration" do
29 | before do
30 | APIMatchers.setup do |config|
31 | config.header_method = :response_header
32 | config.header_content_type_key = 'Content-Type'
33 | end
34 | end
35 |
36 | after do
37 | APIMatchers.setup do |config|
38 | config.header_method = nil
39 | config.header_content_type_key = nil
40 | end
41 | end
42 |
43 | it "should pass if the actual.response_header is equal to application/xml" do
44 | response = OpenStruct.new(:response_header => { 'Content-Type' => "application/xml; charset=utf-8"})
45 | expect(response).to be_xml
46 | end
47 |
48 | it "should fail if the actual.response_header is not equal to application/xml" do
49 | response = OpenStruct.new(:response_header => { "Content-Type" => "application/json; charset=utf-8"})
50 | expect {
51 | expect(response).to be_xml
52 | }.to fail_with(%Q{expected a XML response with 'application/xml; charset=utf-8'. Got: 'application/json; charset=utf-8'.})
53 | end
54 |
55 | it "should fail when pass the actual that have headers but not the content type key" do
56 | response = OpenStruct.new(:response_header => { "foo-baz" => "application/json; charset=utf-8"})
57 | expect {
58 | expect(response).to be_xml
59 | }.to fail_with(%Q{expected a XML response with 'application/xml; charset=utf-8'. Got: '{"foo-baz"=>"application/json; charset=utf-8"}'.})
60 | end
61 | end
62 | end
--------------------------------------------------------------------------------
/spec/api_matchers/http_status_code/base_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::HTTPStatusCode::Base do
4 | let(:setup) { OpenStruct.new }
5 | subject { APIMatchers::HTTPStatusCode::Base.new(setup) }
6 |
7 | describe "#matches?" do
8 | it "should raise Not Implement Exception" do
9 | expect { subject.matches?(302) }.to raise_error(NotImplementedError, "not implemented on #{subject}")
10 | end
11 | end
12 | end
--------------------------------------------------------------------------------
/spec/api_matchers/http_status_code/be_bad_request_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::HTTPStatusCode::BeBadRequest do
4 | describe "should be_bad_request" do
5 | it "should passes if the actual is equal to 400" do
6 | expect(400).to be_bad_request
7 | end
8 |
9 | it "should fails if the actual is not equal to 400" do
10 | expect {
11 | expect(401).to be_bad_request
12 | }.to fail_with(%Q{expected that '401' to be a Bad Request with the status '400'.})
13 | end
14 | end
15 |
16 | describe "should_not be_bad_request" do
17 | it "should passes if the actual is not equal to 400" do
18 | expect(401).not_to be_bad_request
19 | end
20 |
21 | it "should fail if the actual is equal to 400" do
22 | expect {
23 | expect(400).not_to be_bad_request
24 | }.to fail_with(%Q{expected that '400' to NOT be a Bad Request with the status '400'.})
25 | end
26 | end
27 |
28 | describe "with change configuration" do
29 | before do
30 | APIMatchers.setup { |config| config.http_status_method = :http_status }
31 | end
32 |
33 | after do
34 | APIMatchers.setup { |config| config.http_status_method = nil }
35 | end
36 |
37 | it "should pass if the actual.http_status is equal to 400" do
38 | response = OpenStruct.new(:http_status => 400)
39 | expect(response).to be_bad_request
40 | end
41 |
42 | it "should fail if the actual.http_status is not equal to 400" do
43 | response = OpenStruct.new(:http_status => 500)
44 | expect {
45 | expect(response).to be_bad_request
46 | }.to fail_with(%Q{expected that '500' to be a Bad Request with the status '400'.})
47 | end
48 | end
49 | end
--------------------------------------------------------------------------------
/spec/api_matchers/http_status_code/be_forbidden_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::HTTPStatusCode::BeForbidden do
4 | describe "should be_forbidden" do
5 | it "should passes if the actual is equal to 403" do
6 | expect(403).to be_forbidden
7 | end
8 |
9 | it "should fails if the actual is not equal to 403" do
10 | expect {
11 | expect(400).to be_forbidden
12 | }.to fail_with(%Q{expected that '400' to be Forbidden with the status '403'.})
13 | end
14 | end
15 |
16 | describe "should_not be_forbidden" do
17 | it "should pass if the actual is not equal to 403" do
18 | expect(201).not_to be_forbidden
19 | end
20 |
21 | it "should fail if the actual is equal to 403" do
22 | expect {
23 | expect(403).not_to be_forbidden
24 | }.to fail_with(%Q{expected that '403' to NOT be Forbidden.})
25 | end
26 | end
27 |
28 | describe "with change configuration" do
29 | before do
30 | APIMatchers.setup { |config| config.http_status_method = :http_status }
31 | end
32 |
33 | after do
34 | APIMatchers.setup { |config| config.http_status_method = nil }
35 | end
36 |
37 | it "should pass if the actual.http_status is equal to 403" do
38 | response = OpenStruct.new(:http_status => 403)
39 | expect(response).to be_forbidden
40 | end
41 |
42 | it "should fail if the actual.http_status is not equal to 403" do
43 | response = OpenStruct.new(:http_status => 402)
44 | expect {
45 | expect(response).to be_forbidden
46 | }.to fail_with(%Q{expected that '402' to be Forbidden with the status '403'.})
47 | end
48 | end
49 | end
--------------------------------------------------------------------------------
/spec/api_matchers/http_status_code/be_internal_server_error_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::HTTPStatusCode::BeInternalServerError do
4 | describe "should be_internal_server_error" do
5 | it "should passes if the actual is equal to 500" do
6 | expect(500).to be_internal_server_error
7 | end
8 |
9 | it "should fails if the actual is not equal to 500" do
10 | expect {
11 | expect(401).to be_internal_server_error
12 | }.to fail_with(%Q{expected that '401' to be Internal Server Error with the status '500'.})
13 | end
14 | end
15 |
16 | describe "should_not be_internal_server_error" do
17 | it "should passes if the actual is not equal to 500" do
18 | expect(400).not_to be_internal_server_error
19 | end
20 |
21 | it "should fail if the actual is equal to 500" do
22 | expect {
23 | expect(500).not_to be_internal_server_error
24 | }.to fail_with(%Q{expected that '500' to NOT be Internal Server Error.})
25 | end
26 | end
27 |
28 | describe "with change configuration" do
29 | before do
30 | APIMatchers.setup { |config| config.http_status_method = :http_status }
31 | end
32 |
33 | after do
34 | APIMatchers.setup { |config| config.http_status_method = nil }
35 | end
36 |
37 | it "should pass if the actual.http_status is equal to 500" do
38 | response = OpenStruct.new(:http_status => 500)
39 | expect(response).to be_internal_server_error
40 | end
41 |
42 | it "should fail if the actual.http_status is not equal to 500" do
43 | response = OpenStruct.new(:http_status => 402)
44 | expect {
45 | expect(response).to be_internal_server_error
46 | }.to fail_with(%Q{expected that '402' to be Internal Server Error with the status '500'.})
47 | end
48 | end
49 | end
--------------------------------------------------------------------------------
/spec/api_matchers/http_status_code/be_not_found_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::HTTPStatusCode::BeBadRequest do
4 | describe "should be_not_found" do
5 | it "should passes if the actual is equal to 404" do
6 | expect(404).to be_not_found
7 | end
8 |
9 | it "should fails if the actual is not equal to 404" do
10 | expect {
11 | expect(401).to be_not_found
12 | }.to fail_with(%Q{expected that '401' to be Not Found with the status '404'.})
13 | end
14 | end
15 |
16 | describe "should_not be_not_found" do
17 | it "should pass if the actual is not equal to 404" do
18 | expect(401).not_to be_not_found
19 | end
20 |
21 | it "should fail if the actual is equal to 404" do
22 | expect {
23 | expect(404).not_to be_not_found
24 | }.to fail_with(%Q{expected that '404' to NOT be Not Found with the status '404'.})
25 | end
26 | end
27 |
28 | describe "with change configuration" do
29 | before do
30 | APIMatchers.setup { |config| config.http_status_method = :http_status }
31 | end
32 |
33 | after do
34 | APIMatchers.setup { |config| config.http_status_method = nil }
35 | end
36 |
37 | it "should pass if the actual.http_status is equal to 404" do
38 | response = OpenStruct.new(:http_status => 404)
39 | expect(response).to be_not_found
40 | end
41 |
42 | it "should fail if the actual.http_status is not equal to 400" do
43 | response = OpenStruct.new(:http_status => 500)
44 | expect {
45 | expect(response).to be_not_found
46 | }.to fail_with(%Q{expected that '500' to be Not Found with the status '404'.})
47 | end
48 | end
49 | end
--------------------------------------------------------------------------------
/spec/api_matchers/http_status_code/be_ok_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::HTTPStatusCode::BeOk do
4 | describe "should be_ok" do
5 | it "should passes if the actual is equal to 200" do
6 | expect(200).to be_ok
7 | end
8 |
9 | it "should fails if the actual is not equal to 200" do
10 | expect {
11 | expect(201).to be_ok
12 | }.to fail_with(%Q{expected that '201' to be ok with the status '200'.})
13 | end
14 | end
15 |
16 | describe "should_not be_ok_request" do
17 | it "should passes if the actual is not equal to 200" do
18 | expect(201).not_to be_ok
19 | end
20 |
21 | it "should fail if the actual is equal to 200" do
22 | expect {
23 | expect(200).not_to be_ok
24 | }.to fail_with(%Q{expected that '200' to NOT be ok with the status '200'.})
25 | end
26 | end
27 |
28 | describe "with change configuration" do
29 | before do
30 | APIMatchers.setup { |config| config.http_status_method = :http_status }
31 | end
32 |
33 | after do
34 | APIMatchers.setup { |config| config.http_status_method = nil }
35 | end
36 |
37 | it "should pass if the actual.http_status is equal to 200" do
38 | response = OpenStruct.new(:http_status => 200)
39 | expect(response).to be_ok
40 | end
41 |
42 | it "should fail if the actual.http_status is not equal to 200" do
43 | response = OpenStruct.new(:http_status => 500)
44 | expect {
45 | expect(response).to be_ok
46 | }.to fail_with(%Q{expected that '500' to be ok with the status '200'.})
47 | end
48 | end
49 | end
--------------------------------------------------------------------------------
/spec/api_matchers/http_status_code/be_unauthorized_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::HTTPStatusCode::BeUnauthorized do
4 | describe "should be_unauthorized" do
5 | it "should passes if the actual is equal to 401" do
6 | expect(401).to be_unauthorized
7 | end
8 |
9 | it "should fails if the actual is not equal to 401" do
10 | expect {
11 | expect(400).to be_unauthorized
12 | }.to fail_with(%Q{expected that '400' to be Unauthorized with the status '401'.})
13 | end
14 | end
15 |
16 | describe "should_not be_unauthorized" do
17 | it "should pass if the actual is not equal to 401" do
18 | expect(201).not_to be_unauthorized
19 | end
20 |
21 | it "should fail if the actual is equal to 401" do
22 | expect {
23 | expect(401).not_to be_unauthorized
24 | }.to fail_with(%Q{expected that '401' to NOT be Unauthorized.})
25 | end
26 | end
27 |
28 | describe "with change configuration" do
29 | before do
30 | APIMatchers.setup { |config| config.http_status_method = :http_status }
31 | end
32 |
33 | after do
34 | APIMatchers.setup { |config| config.http_status_method = nil }
35 | end
36 |
37 | it "should pass if the actual.http_status is equal to 401" do
38 | response = OpenStruct.new(:http_status => 401)
39 | expect(response).to be_unauthorized
40 | end
41 |
42 | it "should fail if the actual.http_status is not equal to 401" do
43 | response = OpenStruct.new(:http_status => 402)
44 | expect {
45 | expect(response).to be_unauthorized
46 | }.to fail_with(%Q{expected that '402' to be Unauthorized with the status '401'.})
47 | end
48 | end
49 | end
--------------------------------------------------------------------------------
/spec/api_matchers/http_status_code/be_unprocessable_entity_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::HTTPStatusCode::BeUnprocessableEntity do
4 | describe "should be_unprocessable_entity" do
5 | it "should passes if the actual is equal to 422" do
6 | expect(422).to be_unprocessable_entity
7 | end
8 |
9 | it "should fails if the actual is not equal to 422" do
10 | expect {
11 | expect(500).to be_unprocessable_entity
12 | }.to fail_with(%Q{expected that '500' to be Unprocessable entity with the status '422'.})
13 | end
14 | end
15 |
16 | describe "should_not be_unprocessable_entity" do
17 | it "should passes if the actual is not equal to 200" do
18 | expect(400).not_to be_unprocessable_entity
19 | end
20 |
21 | it "should fail if the actual is equal to 200" do
22 | expect {
23 | expect(422).not_to be_unprocessable_entity
24 | }.to fail_with(%Q{expected that '422' to NOT be Unprocessable entity with the status '422'.})
25 | end
26 | end
27 | end
--------------------------------------------------------------------------------
/spec/api_matchers/http_status_code/create_resource_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::HTTPStatusCode::CreateResource do
4 | describe "should create_resource" do
5 | it "should passes if the actual is equal to 201" do
6 | expect(201).to create_resource
7 | end
8 |
9 | it "should fails if the actual is not equal to 201" do
10 | expect {
11 | expect(200).to create_resource
12 | }.to fail_with(%Q{expected that '200' to be Created Resource with the status '201'.})
13 | end
14 | end
15 |
16 | describe "should_not create_resource" do
17 | it "should passes if the actual is not equal to 201" do
18 | expect(401).not_to create_resource
19 | end
20 |
21 | it "should fail if the actual is equal equal to 201" do
22 | expect {
23 | expect(201).not_to create_resource
24 | }.to fail_with(%Q{expected that '201' to NOT be Created Resource.})
25 | end
26 | end
27 |
28 | describe "with change configuration" do
29 | before do
30 | APIMatchers.setup { |config| config.http_status_method = :http_status }
31 | end
32 |
33 | after do
34 | APIMatchers.setup { |config| config.http_status_method = nil }
35 | end
36 |
37 | it "should pass if the actual.http_status is equal to 201" do
38 | response = OpenStruct.new(:http_status => 201)
39 | expect(response).to create_resource
40 | end
41 |
42 | it "should fail if the actual.http_status is not equal to 201" do
43 | response = OpenStruct.new(:http_status => 402)
44 | expect {
45 | expect(response).to create_resource
46 | }.to fail_with(%Q{expected that '402' to be Created Resource with the status '201'.})
47 | end
48 | end
49 | end
--------------------------------------------------------------------------------
/spec/api_matchers/response_body/base_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::ResponseBody::Base do
4 | let(:setup) { OpenStruct.new(:response_body_method => :body) }
5 | subject { APIMatchers::ResponseBody::Base.new(setup: setup, expected_node: :status) }
6 |
7 | describe "#matches?" do
8 | it "should raise Not Implemented Error" do
9 | expect {
10 | subject.matches?("foo")
11 | }.to raise_error(NotImplementedError, "not implemented on #{subject}")
12 | end
13 | end
14 |
15 | describe "#setup" do
16 | it "should read from the initialize" do
17 | expect(subject.setup).to equal setup
18 | end
19 | end
20 |
21 | describe "#expected_node" do
22 | it "should read from the initialize" do
23 | expect(subject.expected_node).to equal :status
24 | end
25 | end
26 |
27 | describe "#response_body" do
28 | let(:body) { { :foo => :bar}.to_json }
29 |
30 | context 'when have configuration' do
31 | it "should call the method when is config" do
32 | subject.actual = OpenStruct.new(:body => body)
33 | expect(subject.response_body).to eql body
34 | end
35 | end
36 |
37 | context 'when dont have configuration' do
38 | let(:setup) { OpenStruct.new(:response_body_method => nil) }
39 | subject { APIMatchers::ResponseBody::Base.new(setup: setup, expected_node: :status) }
40 |
41 | it "should return the actual when do not have config" do
42 | subject.actual = body
43 | expect(subject.response_body).to eql body
44 | end
45 | end
46 | end
47 | end
--------------------------------------------------------------------------------
/spec/api_matchers/response_body/have_json_node_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::ResponseBody::HaveJsonNode do
4 | describe "actual).to have_json_node" do
5 | context 'expected key and value in top level' do
6 | it "pass when the expected key exist" do
7 | expect({ :product => 'gateway' }.to_json).to have_json_node(:product)
8 | end
9 |
10 | it "fail when the expected key does not exist" do
11 | expect {
12 | expect({ :product => 'pabx' }.to_json).to have_json_node(:developers)
13 | }.to fail_with(%Q{expected to have node called: 'developers'. Got: '{"product":"pabx"}'})
14 | end
15 |
16 | it "pass when the expected key exist with the expected value" do
17 | expect({ :product => 'payment-gateway' }.to_json).to have_json_node(:product).with('payment-gateway')
18 | end
19 |
20 | it "pass when the expected key exist with the expected value (as integer)" do
21 | expect({ :number => 1 }.to_json).to have_json_node(:number).with(1)
22 | end
23 |
24 | it "pass when the expected key exist with the expected value (as boolean, true)" do
25 | expect({ :number => true }.to_json).to have_json_node(:number).with(true)
26 | end
27 |
28 | it "pass when the expected key exist with the expected value (as boolean, false)" do
29 | expect({ :number => false }.to_json).to have_json_node(:number).with(false)
30 | end
31 |
32 | it "pass when the expected key exist but the expected value is wrong (as boolean, true)" do
33 | expect({ :number => true }.to_json).not_to have_json_node(:number).with(false)
34 | end
35 |
36 | it "pass when the expected key exist but the expected value is wrong (as boolean, false)" do
37 | expect({ :number => false }.to_json).not_to have_json_node(:number).with(true)
38 | end
39 |
40 | it "pass when the expected key exists with the expected value (as DateTime)" do
41 | now = DateTime.now.to_s
42 | expect({ :date => now }.to_json).to have_json_node(:date).with(now)
43 | end
44 |
45 | it "pass when the expected key exists with the expected value (as Date)" do
46 | now = Date.today
47 | expect({ :date => now }.to_json).to have_json_node(:date).with(now)
48 | end
49 |
50 | it "pass when the expected key exists with the expected value (as Time)" do
51 | now = Time.now.to_s
52 | expect({ :time => now }.to_json).to have_json_node(:time).with(now)
53 | end
54 |
55 | it "fail when the expected key exist but the expected value don't exist" do
56 | expect {
57 | expect({ :product => 'payment-gateway' }.to_json).to have_json_node(:product).with('email-marketing')
58 | }.to fail_with(%Q{expected to have node called: 'product' with value: 'email-marketing'. Got: '{"product":"payment-gateway"}'})
59 | end
60 |
61 | it "not parse the matcher for json when you pass a xml" do
62 | expect {
63 | expect("webdesk").to have_json_node(:name).with('webdesk')
64 | }.to raise_error(APIMatchers::InvalidJSON, "Invalid JSON: 'webdesk'")
65 | end
66 | end
67 |
68 | context 'expected key and nil value' do
69 | it "pass when the expected key exists" do
70 | expect({ :product => nil }.to_json).to have_json_node(:product)
71 | end
72 |
73 | it "pass when the expected key exists and the expected value is nil" do
74 | expect({ :product => nil }.to_json).to have_json_node(:product).with( nil )
75 | end
76 |
77 | it "fail when the expected key exist but the expected value don't exist" do
78 | expect {
79 | expect({ :product => nil }.to_json).to have_json_node(:product).with('email-marketing')
80 | }.to fail_with(%Q{expected to have node called: 'product' with value: 'email-marketing'. Got: '{"product":null}'})
81 | end
82 | end
83 |
84 | context 'expected key and value in more deep in the JSON' do
85 | context '.to_json used' do
86 | it "pass when the expected key exist" do
87 | expect({ :transaction => { :id => 150 } }.to_json).to have_json_node(:id)
88 | end
89 |
90 | it "pass when the expected key and expected value exist" do
91 | expect({ :transaction => { :error => { :code => '999' } } }.to_json).to have_json_node(:code).with('999')
92 | end
93 |
94 | it "pass when the expected key and expected value exist in very deep" do
95 | expect({ :first=>"A", :second=>nil, :third=>{ :stuff => { :first_stuff=>{ :color=>"green", :size=>"small", :shape=>"circle", :uid=>"first_stuff"}, :second_stuff=>{ :color=>"blue", :size=>"large", :shape=>"square", :uid=>"second_stuff"}}, :junk=>[{"name"=>"junk_one", :uid=>"junk_one", :stuff_uid=>"first_stuff"}, { :name=>"junk_two", :uid=>"junk_two", :stuff_uid=>"second_stuff"}]}}.to_json).to have_json_node( :junk )
96 | end
97 |
98 | it "pass when the expected key and expected value exist in very deep" do
99 | expect({ :first=>"A", :second=>nil, :third=>{ :stuff => { :first_stuff=>{ :color=>"green", :size=>"small", :shape=>"circle", :uid=>"first_stuff"}, :second_stuff=>{ :color=>"blue", :size=>"large", :shape=>"square", :uid=>"second_stuff"}}, :junk=>[{"name"=>"junk_one", :uid=>"junk_one", :stuff_uid=>"first_stuff"}, { :name=>"junk_two", :uid=>"junk_two", :stuff_uid=>"second_stuff"}]}}.to_json).to have_json_node( :name ).with( "junk_two" )
100 | end
101 |
102 | it "fail when the expected key does not exist" do
103 | expect {
104 | expect({ :transaction => { :id => 150, :error => {} } }.to_json).to have_json_node(:code)
105 | }.to fail_with(%Q{expected to have node called: 'code'. Got: '{"transaction":{"id":150,"error":{}}}'})
106 | end
107 |
108 | it "fail when the expected key exist but don't exist the expected value" do
109 | expect {
110 | expect({ :transaction => { :id => 150, :error => { :code => '999' } } }.to_json).to have_json_node(:code).with('001')
111 | }.to fail_with(%Q{expected to have node called: 'code' with value: '001'. Got: '{"transaction":{"id":150,"error":{"code":"999"}}}'})
112 | end
113 | end
114 | context 'json string used' do
115 | it "pass when the expected key exist" do
116 | expect('{ "transaction": {"id": 150 } }').to have_json_node(:id)
117 | end
118 |
119 | it "pass when the expected key and expected value exist" do
120 | expect('{ "transaction": {"error": { "code": "999" } } }').to have_json_node(:code).with('999')
121 | end
122 |
123 | it "pass when the expected key exist with the expected value (as integer)" do
124 | expect('{"number":1 }').to have_json_node(:number).with(1)
125 | end
126 |
127 | it "pass when the expected key exist with the expected value (as boolean)" do
128 | expect('{"boolean":true}').to have_json_node(:boolean).with(true)
129 | end
130 |
131 | it "pass when the expected key exists with the expected value (as DateTime)" do
132 | now = DateTime.parse( "2012-09-18T15:42:12-07:00" )
133 | expect('{"date": "2012-09-18T15:42:12-07:00"}').to have_json_node(:date).with(now)
134 | end
135 |
136 | it "pass when the expected key exists with the expected value (as Date)" do
137 | now = Date.parse( "2012-09-18" )
138 | expect('{"date": "2012-09-18"}').to have_json_node(:date).with(now)
139 | end
140 |
141 | it "pass when the expected key exists with the expected value (as Time)" do
142 | now = Time.parse("2012-09-18T15:42:12Z")
143 | expect('{"time": "2012-09-18T15:42:12+00:00"}').to have_json_node(:time).with(now)
144 | end
145 |
146 | it "pass when the expected key exist with the expected value (as boolean) in a multi node" do
147 | expect('{"uid":"123456","boolean":true}').to have_json_node(:boolean).with(true)
148 | end
149 |
150 | it "pass when the expected key and expected value exist in very deep" do
151 | expect('{"first":"A","second":null,"third":{"stuff":{"first_stuff":{"color":"green","size":"small","shape":"circle","uid":"first_stuff"},"second_stuff":{"color":"blue","size":"large","shape":"square","uid":"second_stuff"}},"junk":[{"name":"junk_one","uid":"junk_one","stuff_uid":"first_stuff"},{"name":"junk_two","uid":"junk_two","stuff_uid":"second_stuff"}]}}').to have_json_node( :junk )
152 | end
153 |
154 | it "pass when the expected key and expected value exist in very deep" do
155 | expect('{"first":"A","second":null,"third":{"stuff":{"first_stuff":{"color":"green","size":"small","shape":"circle","uid":"first_stuff"},"second_stuff":{"color":"blue","size":"large","shape":"square","uid":"second_stuff"}},"junk":[{"name":"junk_one","uid":"junk_one","stuff_uid":"first_stuff"},{"name":"junk_two","uid":"junk_two","stuff_uid":"second_stuff"}]}}').to have_json_node( :name ).with( "junk_two" )
156 | end
157 |
158 | it "pass when the expected key and including text exist" do
159 | expect('{"Key":"A=123456-abcdef-09876-ghijkl; path=/; expires=Sun, 05-Sep-2032 05:50:39 GMT\nB=ABCDEF123456; path=/; expires=Sun, 05-Sep-2032 05:50:39 GMT", "Content-Type":"application/json; charset=utf-8"}').to have_json_node( "Key" ).including_text( "123456-abcdef-09876-ghijkl" )
160 | end
161 |
162 | it "fail when the expected key does not exist" do
163 | expect {
164 | expect('{"transaction":{"id":150,"error":{}}}').to have_json_node(:code)
165 | }.to fail_with(%Q{expected to have node called: 'code'. Got: '{"transaction":{"id":150,"error":{}}}'})
166 | end
167 |
168 | it "fail when the expected key exist but don't exist the expected value" do
169 | expect {
170 | expect('{"transaction":{"id":150,"error":{"code":"999"}}}').to have_json_node(:code).with('001')
171 | }.to fail_with(%Q{expected to have node called: 'code' with value: '001'. Got: '{"transaction":{"id":150,"error":{"code":"999"}}}'})
172 | end
173 | end
174 | end
175 |
176 | context "including_text" do
177 | let(:json) do
178 | { :transaction => { :error => { :message => "Transaction error: Name can't be blank" } } }.to_json
179 | end
180 |
181 | it "pass when the expected is included in the actual" do
182 | expect({ :transaction => { :error => { :message => "Transaction error: Name can't be blank" } } }.to_json).to have_json_node(:message).including_text("Transaction error")
183 | end
184 |
185 | it "fail when the expected is not included in the actual" do
186 | expect {
187 | expect(json).to have_json_node(:message).including_text("Fox on the run")
188 | }.to fail_with(%Q{expected to have node called: 'message' including text: 'Fox on the run'. Got: '{"transaction":{"error":{"message":"Transaction error: Name can't be blank"}}}'})
189 | end
190 | end
191 | end
192 |
193 | describe "actual).not_to have_json_node" do
194 | it "pass when don't have the expected node in root level" do
195 | expect({ :product => 'gateway' }.to_json).not_to have_json_node(:status)
196 | end
197 |
198 | it "pass when don't have the expected node in any level" do
199 | expect({ :transaction => { :id => 12, :status => 'paid' } }.to_json).not_to have_json_node(:error)
200 | end
201 |
202 | it "fail when the expected key exist" do
203 | expect {
204 | expect({ :status => 'paid' }.to_json).not_to have_json_node(:status)
205 | }.to fail_with(%Q{expected to NOT have node called: 'status'. Got: '{"status":"paid"}'})
206 | end
207 |
208 | it "pass when have the expected key but have a different value" do
209 | expect({ :status => 'paid' }.to_json).not_to have_json_node(:status).with('not_authorized')
210 | end
211 |
212 | it "fail when have the expected key and have the expected value" do
213 | expect {
214 | expect({ :status => 'paid' }.to_json).not_to have_json_node(:status).with('paid')
215 | }.to fail_with(%Q{expected to NOT have node called: 'status' with value: 'paid'. Got: '{"status":"paid"}'})
216 | end
217 |
218 | context "including_text" do
219 | it "pass when the expected is NOT included in the actual" do
220 | expect({ :transaction => { :error => { :message => "Transaction error: Name can't be blank" } } }.to_json).not_to have_json_node(:message).including_text("Love gun")
221 | end
222 |
223 | it "fail when the expected is included in the actual" do
224 | expect {
225 | expect({ :transaction => { :error => { :message => "Transaction error: Name can't be blank" } } }.to_json).not_to have_json_node(:message).including_text("Transaction error")
226 | }.to fail_with(%Q{expected to NOT have node called: 'message' including text: 'Transaction error'. Got: '{"transaction":{"error":{"message":"Transaction error: Name can't be blank"}}}'})
227 | end
228 | end
229 | end
230 |
231 | describe "some assumptions" do
232 | it "pass when have the json node name" do
233 | expect('{ "transaction": { "id": 54, "status": "paid" } }').to have_json_node(:transaction)
234 | end
235 |
236 | it "pass when have json node with integer value" do
237 | expect('{ "transaction": { "id": 54, "status": "paid" } }').to have_json_node(:id).with(54)
238 | end
239 |
240 | it "should have json node including text" do
241 | expect('{"error": "Transaction error: Name cant be blank"}').to have_json_node(:error).including_text("Transaction error")
242 | end
243 |
244 | it "pass have json node with boolean value" do
245 | expect('{"creditcard": true}').to have_json_node(:creditcard).with(true)
246 | end
247 |
248 | it "pass have json node with string" do
249 | expect('{ "error": "not_authorized", "transaction": { "id": "55" } }').to have_node(:error).with('not_authorized')
250 | end
251 |
252 | it "pass have json node with integer" do
253 | expect('{"parcels": 1 }').to have_node(:parcels).with(1)
254 | end
255 | end
256 |
257 | describe "with change configuration" do
258 | before do
259 | APIMatchers.setup { |config| config.response_body_method = :response_body }
260 | end
261 |
262 | after do
263 | APIMatchers.setup { |config| config.response_body_method = nil }
264 | end
265 |
266 | it "pass if the actual.http_status is equal to 400" do
267 | response = OpenStruct.new(:response_body => { :foo => :bar }.to_json)
268 | expect(response).to have_json_node(:foo).with('bar')
269 | end
270 |
271 | it "fail if the actual.http_status is not equal to 400" do
272 | response = OpenStruct.new(:response_body => { :baz => :foo}.to_json)
273 | expect {
274 | expect(response).to have_json_node(:bar)
275 | }.to fail_with(%Q{expected to have node called: 'bar'. Got: '{"baz":"foo"}'})
276 | end
277 | end
278 | end
279 |
--------------------------------------------------------------------------------
/spec/api_matchers/response_body/have_json_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::ResponseBody::HaveJson do
4 | describe "actual).to have_json" do
5 | context 'when pass' do
6 | it 'equal json' do
7 | expect(['Petshop', 'Dogs'].to_json).to have_json(['Petshop', 'Dogs'])
8 | end
9 |
10 | it 'compares with Hash too' do
11 | expect({ 'offers' => [10, 90] }.to_json).to have_json({ 'offers' => [10,90] })
12 | end
13 | end
14 |
15 | context 'when fails' do
16 | it 'fails with the expected response nd the actual body in the fail message' do
17 | expect {
18 | expect(['Petshop', 'Cats'].to_json).to have_json(['Petshop', 'Dogs'])
19 | }.to fail_with(%Q{expect to have json: '["Petshop", "Dogs"]'. Got: '["Petshop", "Cats"]'.})
20 | end
21 | end
22 | end
23 |
24 | describe "actual).not_to have_json" do
25 | context 'when pass' do
26 | it 'different json' do
27 | expect(['Petshop', 'Cats'].to_json).not_to have_json(['Petshop', 'Dogs'])
28 | end
29 | end
30 |
31 | context 'when fails' do
32 | it 'equal json returns the fail message for expect not to' do
33 | expect {
34 | expect(['Petshop', 'Cats'].to_json).not_to have_json(['Petshop', 'Cats'])
35 | }.to fail_with(%Q{expect to NOT have json: '["Petshop","Cats"]'.})
36 | end
37 | end
38 | end
39 | end
--------------------------------------------------------------------------------
/spec/api_matchers/response_body/have_node_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::ResponseBody::HaveNode do
4 | describe "in json" do
5 | before do
6 | APIMatchers.setup { |config| config.have_node_matcher = :json }
7 | end
8 |
9 | it "should parse the matcher for json" do
10 | expect({ :product => 'chat' }.to_json).to have_node(:product).with('chat')
11 | end
12 | end
13 |
14 | describe "in xml" do
15 | before do
16 | APIMatchers.setup { |config| config.have_node_matcher = :xml }
17 | end
18 |
19 | it "should parse the matcher for xml" do
20 | expect("chat").to have_node(:product).with('chat')
21 | end
22 |
23 | after do
24 | APIMatchers.setup { |config| config.have_node_matcher = :json }
25 | end
26 | end
27 | end
--------------------------------------------------------------------------------
/spec/api_matchers/response_body/have_xml_node_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | RSpec.describe APIMatchers::ResponseBody::HaveXmlNode do
4 | describe "actual).to have_xml_node" do
5 | context 'expected key and value in top level' do
6 | it "should pass when the expected key exist" do
7 | expect("gateway").to have_xml_node(:product)
8 | end
9 |
10 | it "should fail when the expected key does not exist" do
11 | expect {
12 | expect("pabx").to have_xml_node(:developers)
13 | }.to fail_with(%Q{expected to have node called: 'developers'. Got: 'pabx'})
14 | end
15 |
16 | it "should pass when the expected key exist with the expected value" do
17 | expect("payment-gateway").to have_xml_node(:product).with('payment-gateway')
18 | end
19 |
20 | it "should fail when the expected key exist but the expected value don't exist" do
21 | expect {
22 | expect("payment-gateway").to have_xml_node(:product).with('email-marketing')
23 | }.to fail_with(%Q{expected to have node called: 'product' with value: 'email-marketing'. Got: 'payment-gateway'})
24 | end
25 |
26 | it "should not parse the matcher for xml when you pass a json" do
27 | expect {
28 | expect({ :name => 'webdesk'}.to_json).to have_xml_node(:name).with('webdesk')
29 | }.to fail_with(%Q{expected to have node called: 'name' with value: 'webdesk'. Got: '{"name":"webdesk"}'})
30 | end
31 | end
32 |
33 | context 'expected key and value in more deep in the XML' do
34 | it "should pass when the expected key exist" do
35 | expect("150").to have_xml_node(:id)
36 | end
37 |
38 | it "should pass when the expected key and expected value exist" do
39 | expect("999
").to have_xml_node(:code).with('999')
40 | end
41 |
42 | it "should fail when the expected key does not exist" do
43 | expect {
44 | expect("").to have_xml_node(:code)
45 | }.to fail_with(%Q{expected to have node called: 'code'. Got: ''})
46 | end
47 |
48 | it "should fail when the expected key exist but don't exist the expected value" do
49 | expect {
50 | expect("999
").to have_xml_node(:code).with('001')
51 | }.to fail_with(%Q{expected to have node called: 'code' with value: '001'. Got: '999
'})
52 | end
53 | end
54 |
55 | context "including_text" do
56 | it "should pass when the expected is included in the actual" do
57 | expect("Transaction error: Name can't be blank").to have_xml_node(:message).including_text("Transaction error")
58 | end
59 |
60 | it "should fail when the expected is not included in the actual" do
61 | expect {
62 | expect("Transaction error: Name can't be blank").to have_xml_node(:message).including_text("Fox on the run")
63 | }.to fail_with(%Q{expected to have node called: 'message' including text: 'Fox on the run'. Got: 'Transaction error: Name can't be blank'})
64 | end
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 | expect(%{
70 |
71 | 4
72 | 2
73 |
74 | }).to have_xml_node(:id).with(2)
75 | end
76 |
77 | it "should fail when the expected is not included in the actual (1 level)" do
78 | expect(%{
79 |
80 | 4
81 | 2
82 |
83 | }).not_to have_xml_node(:id).with(3)
84 | end
85 |
86 | it "should pass when the expected is included in the actual (2 levels)" do
87 | expect(%{
88 |
89 |
90 |
91 |
92 | }).to have_xml_node(:id).with(2)
93 | end
94 |
95 | it "should fail when the expected is not included in the actual (2 levels)" do
96 | expect(%{
97 |
98 |
99 |
100 |
101 | }).not_to have_xml_node(:id).with(3)
102 | end
103 | end
104 | end
105 |
106 | describe "actual).not_to have_xml_node" do
107 | it "should pass when don't have the expected node in root level" do
108 | expect("gateway").not_to have_xml_node(:status)
109 | end
110 |
111 | it "should pass when don't have the expected node in any level" do
112 | expect("12paid").not_to have_xml_node(:error)
113 | end
114 |
115 | it "should fail when the expected key exist" do
116 | expect {
117 | expect("paid").not_to have_xml_node(:status)
118 | }.to fail_with(%Q{expected to NOT have node called: 'status'. Got: 'paid'})
119 | end
120 |
121 | it "should pass when have the expected key but have a different value" do
122 | expect("paid").not_to have_xml_node(:status).with('not_authorized')
123 | end
124 |
125 | it "should fail when have the expected key and have the expected value" do
126 | expect {
127 | expect("paid").not_to have_xml_node(:status).with('paid')
128 | }.to fail_with(%Q{expected to NOT have node called: 'status' with value: 'paid'. Got: 'paid'})
129 | end
130 |
131 | context "including_text" do
132 | it "should pass when the expected is included in the actual" do
133 | expect("Transaction error: Name can't be blank").not_to have_xml_node(:message).including_text("Girls of Summer")
134 | end
135 |
136 | it "should fail when the expected is not included in the actual" do
137 | expect {
138 | expect("Transaction error: Name can't be blank").not_to have_xml_node(:message).including_text("Transaction error")
139 | }.to fail_with(%Q{expected to NOT have node called: 'message' including text: 'Transaction error'. Got: 'Transaction error: Name can't be blank'})
140 | end
141 | end
142 | end
143 |
144 |
145 | describe "with change configuration" do
146 | before do
147 | APIMatchers.setup { |config| config.response_body_method = :response_body }
148 | end
149 |
150 | after do
151 | APIMatchers.setup { |config| config.response_body_method = nil }
152 | end
153 |
154 | it "should pass if the actual.http_status is equal to 400" do
155 | response = OpenStruct.new(:response_body => "bar")
156 | expect(response).to have_xml_node(:foo).with('bar')
157 | end
158 |
159 | it "should fail if the actual.http_status is not equal to 400" do
160 | response = OpenStruct.new(:response_body => "bar")
161 | expect {
162 | expect(response).to have_xml_node(:bar)
163 | }.to fail_with(%Q{expected to have node called: 'bar'. Got: 'bar'})
164 | end
165 | end
166 | end
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | require 'active_support'
2 | require 'api_matchers'
3 | require 'ostruct'
4 |
5 | RSpec.configure do |config|
6 | config.disable_monkey_patching!
7 | config.include APIMatchers::RSpecMatchers
8 |
9 | def fail_with(message)
10 | raise_error(RSpec::Expectations::ExpectationNotMetError, message)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------