hops-airborne 0.2.15

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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +38 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +12 -0
  6. data/Gemfile +10 -0
  7. data/LICENSE +9 -0
  8. data/README.md +429 -0
  9. data/airborne.gemspec +19 -0
  10. data/lib/airborne/base.rb +82 -0
  11. data/lib/airborne/optional_hash_type_expectations.rb +23 -0
  12. data/lib/airborne/path_matcher.rb +101 -0
  13. data/lib/airborne/rack_test_requester.rb +18 -0
  14. data/lib/airborne/request_expectations.rb +285 -0
  15. data/lib/airborne/rest_client_requester.rb +33 -0
  16. data/lib/airborne.rb +29 -0
  17. data/spec/airborne/base_spec.rb +55 -0
  18. data/spec/airborne/client_requester_spec.rb +42 -0
  19. data/spec/airborne/delete_spec.rb +9 -0
  20. data/spec/airborne/expectations/expect_header_contains_spec.rb +21 -0
  21. data/spec/airborne/expectations/expect_header_spec.rb +21 -0
  22. data/spec/airborne/expectations/expect_json_keys_path_spec.rb +15 -0
  23. data/spec/airborne/expectations/expect_json_keys_spec.rb +21 -0
  24. data/spec/airborne/expectations/expect_json_lambda_spec.rb +9 -0
  25. data/spec/airborne/expectations/expect_json_options_spec.rb +65 -0
  26. data/spec/airborne/expectations/expect_json_path_spec.rb +108 -0
  27. data/spec/airborne/expectations/expect_json_regex_spec.rb +33 -0
  28. data/spec/airborne/expectations/expect_json_sizes_spec.rb +33 -0
  29. data/spec/airborne/expectations/expect_json_spec.rb +27 -0
  30. data/spec/airborne/expectations/expect_json_types_date_spec.rb +52 -0
  31. data/spec/airborne/expectations/expect_json_types_lambda_spec.rb +9 -0
  32. data/spec/airborne/expectations/expect_json_types_optional_spec.rb +15 -0
  33. data/spec/airborne/expectations/expect_json_types_options_spec.rb +59 -0
  34. data/spec/airborne/expectations/expect_json_types_path_spec.rb +65 -0
  35. data/spec/airborne/expectations/expect_json_types_spec.rb +85 -0
  36. data/spec/airborne/expectations/expect_status_spec.rb +23 -0
  37. data/spec/airborne/head_spec.rb +10 -0
  38. data/spec/airborne/options_spec.rb +10 -0
  39. data/spec/airborne/patch_spec.rb +9 -0
  40. data/spec/airborne/path_spec.rb +34 -0
  41. data/spec/airborne/post_spec.rb +17 -0
  42. data/spec/airborne/put_spec.rb +9 -0
  43. data/spec/airborne/rack/rack_sinatra_spec.rb +43 -0
  44. data/spec/spec_helper.rb +14 -0
  45. data/spec/stub_helper.rb +45 -0
  46. data/spec/test_responses/array_of_types.json +9 -0
  47. data/spec/test_responses/array_of_values.json +5 -0
  48. data/spec/test_responses/array_response.json +5 -0
  49. data/spec/test_responses/array_with_index.json +6 -0
  50. data/spec/test_responses/array_with_nested.json +16 -0
  51. data/spec/test_responses/array_with_nested_bad_data.json +15 -0
  52. data/spec/test_responses/array_with_partial_nested.json +12 -0
  53. data/spec/test_responses/date_is_null_response.json +3 -0
  54. data/spec/test_responses/date_response.json +3 -0
  55. data/spec/test_responses/hash_property.json +3 -0
  56. data/spec/test_responses/invalid_get.json +1 -0
  57. data/spec/test_responses/invalid_json.json +1 -0
  58. data/spec/test_responses/numeric_property.json +6 -0
  59. data/spec/test_responses/simple_delete.json +4 -0
  60. data/spec/test_responses/simple_get.json +5 -0
  61. data/spec/test_responses/simple_json.json +5 -0
  62. data/spec/test_responses/simple_nested_path.json +12 -0
  63. data/spec/test_responses/simple_patch.json +4 -0
  64. data/spec/test_responses/simple_path_get.json +8 -0
  65. data/spec/test_responses/simple_post.json +4 -0
  66. data/spec/test_responses/simple_put.json +4 -0
  67. metadata +206 -0
@@ -0,0 +1,101 @@
1
+ module Airborne
2
+ class PathError < StandardError; end
3
+
4
+ module PathMatcher
5
+ def get_by_path(path, json, &block)
6
+ fail PathError, "Invalid Path, contains '..'" if /\.\./ =~ path
7
+ type = false
8
+ parts = path.split('.')
9
+ parts.each_with_index do |part, index|
10
+ if part == '*' || part == '?'
11
+ ensure_array(path, json)
12
+ type = part
13
+ if index < parts.length.pred
14
+ walk_with_path(type, index, path, parts, json, &block) && return
15
+ end
16
+ next
17
+ end
18
+ begin
19
+ json = process_json(part, json)
20
+ rescue
21
+ raise PathError, "Expected #{json.class}\nto be an object with property #{part}"
22
+ end
23
+ end
24
+ if type == '*'
25
+ expect_all(json, &block)
26
+ elsif type == '?'
27
+ expect_one(path, json, &block)
28
+ else
29
+ yield json
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def walk_with_path(type, index, path, parts, json, &block)
36
+ last_error = nil
37
+ item_count = json.length
38
+ error_count = 0
39
+ json.each do |element|
40
+ begin
41
+ sub_path = parts[(index.next)...(parts.length)].join('.')
42
+ get_by_path(sub_path, element, &block)
43
+ rescue Exception => e
44
+ last_error = e
45
+ error_count += 1
46
+ end
47
+ ensure_match_all(last_error) if type == '*'
48
+ ensure_match_one(path, item_count, error_count) if type == '?'
49
+ end
50
+ end
51
+
52
+ def process_json(part, json)
53
+ if index?(part) && json.is_a?(Array)
54
+ part = part.to_i
55
+ json = json[part]
56
+ else
57
+ json = json[part.to_sym]
58
+ end
59
+ json
60
+ end
61
+
62
+ def index?(part)
63
+ part =~ /^\d+$/
64
+ end
65
+
66
+ def expect_one(path, json, &block)
67
+ item_count = json.length
68
+ error_count = 0
69
+ json.each do |part|
70
+ begin
71
+ yield part
72
+ rescue Exception
73
+ error_count += 1
74
+ ensure_match_one(path, item_count, error_count)
75
+ end
76
+ end
77
+ end
78
+
79
+ def expect_all(json, &block)
80
+ last_error = nil
81
+ begin
82
+ json.each { |part| yield part }
83
+ rescue Exception => e
84
+ last_error = e
85
+ end
86
+ ensure_match_all(last_error)
87
+ end
88
+
89
+ def ensure_match_one(path, item_count, error_count)
90
+ fail RSpec::Expectations::ExpectationNotMetError, "Expected one object in path #{path} to match provided JSON values" if item_count == error_count
91
+ end
92
+
93
+ def ensure_match_all(error)
94
+ fail error unless error.nil?
95
+ end
96
+
97
+ def ensure_array(path, json)
98
+ fail RSpec::Expectations::ExpectationNotMetError, "Expected #{path} to be array got #{json.class} from JSON response" unless json.class == Array
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,18 @@
1
+ require 'rack/test'
2
+
3
+ module Airborne
4
+ module RackTestRequester
5
+ def make_request(method, url, options = {})
6
+ headers = options[:headers] || {}
7
+ base_headers = Airborne.configuration.headers || {}
8
+ headers = base_headers.merge(headers)
9
+ browser = Rack::Test::Session.new(Rack::MockSession.new(Airborne.configuration.rack_app))
10
+ headers.each { |name, value| browser.header(name, value) }
11
+ browser.send(method, url, options[:body] || {}, headers)
12
+ Rack::MockResponse.class_eval do
13
+ alias_method :code, :status
14
+ end
15
+ browser.last_response
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,285 @@
1
+ require 'rspec'
2
+ require 'date'
3
+ require 'rack/utils'
4
+
5
+ module Airborne
6
+ class ExpectationError < StandardError; end
7
+ module RequestExpectations
8
+ include RSpec
9
+ include PathMatcher
10
+
11
+ def expect_json_types(*args)
12
+ call_with_path(args) do |param, body|
13
+ expect_json_types_impl(param, body)
14
+ end
15
+ end
16
+
17
+ def expect_json(*args)
18
+ call_with_path(args) do |param, body|
19
+ expect_json_impl(param, body)
20
+ end
21
+ end
22
+
23
+ def expect_json_keys(*args)
24
+ call_with_path(args) do |param, body|
25
+ expect(body.keys).to include(*param)
26
+ end
27
+ end
28
+
29
+ def expect_json_sizes(*args)
30
+ args.push(convert_expectations_for_json_sizes(args.pop))
31
+
32
+ expect_json_types(*args)
33
+ end
34
+
35
+ def expect_status(code)
36
+ expect(response.code).to eq(resolve_status(code, response.code))
37
+ end
38
+
39
+ def expect_header(key, content)
40
+ expect_header_impl(key, content)
41
+ end
42
+
43
+ def expect_header_contains(key, content)
44
+ expect_header_impl(key, content, true)
45
+ end
46
+
47
+ def optional(hash)
48
+ OptionalHashTypeExpectations.new(hash)
49
+ end
50
+
51
+ def regex(reg)
52
+ Regexp.new(reg)
53
+ end
54
+
55
+ def date
56
+ ->(value) { yield DateTime.parse(value) }
57
+ end
58
+
59
+ private
60
+
61
+ def expect_header_impl(key, content, contains = nil)
62
+ header = headers[key]
63
+ if header
64
+ if contains
65
+ expect(header.downcase).to include(content.downcase)
66
+ else
67
+ expect(header.downcase).to eq(content.downcase)
68
+ end
69
+ else
70
+ fail RSpec::Expectations::ExpectationNotMetError, "Header #{key} not present in the HTTP response"
71
+ end
72
+ end
73
+
74
+ def expect_json_impl(expected, actual)
75
+ return if nil_optional_hash?(expected, actual)
76
+
77
+ actual = actual.to_s if expected.is_a?(Regexp)
78
+
79
+ return expect(actual).to match(expected) if property?(expected)
80
+
81
+ keys = []
82
+
83
+ keys << expected.keys if match_expected?
84
+ keys << actual.keys if match_actual?
85
+ keys = expected.keys & actual.keys if match_none?
86
+
87
+ keys.flatten.uniq.each do |prop|
88
+ expected_value = extract_expected_value(expected, prop)
89
+ actual_value = extract_actual(actual, prop)
90
+
91
+ next expect_json_impl(expected_value, actual_value) if hash?(expected_value) && hash?(actual_value)
92
+ next expected_value.call(actual_value) if expected_value.is_a?(Proc)
93
+ next expect(actual_value.to_s).to match(expected_value) if expected_value.is_a?(Regexp)
94
+
95
+ expect(actual_value).to eq(expected_value)
96
+ end
97
+ end
98
+
99
+ def expect_json_types_impl(expected, actual)
100
+ return if nil_optional_hash?(expected, actual)
101
+
102
+ @mapper ||= get_mapper
103
+
104
+ actual = convert_to_date(actual) if ((expected == :date) || (expected == :date_or_null))
105
+
106
+ return expect_type(expected, actual) if expected.is_a?(Symbol)
107
+ return expected.call(actual) if expected.is_a?(Proc)
108
+
109
+ keys = []
110
+
111
+ keys << expected.keys if match_expected?
112
+ keys << actual.keys if match_actual?
113
+ keys = expected.keys & actual.keys if match_none?
114
+
115
+ keys.flatten.uniq.each do |prop|
116
+ type = extract_expected_type(expected, prop)
117
+ value = extract_actual(actual, prop)
118
+ value = convert_to_date(value) if ((type == :date) || (type == :date_or_null))
119
+
120
+ next expect_json_types_impl(type, value) if hash?(type)
121
+ next type.call(value) if type.is_a?(Proc)
122
+
123
+ type_string = type.to_s
124
+
125
+ if type_string.include?('array_of') && !(type_string.include?('or_null') && value.nil?)
126
+ check_array_types(value, prop, type)
127
+ else
128
+ expect_type(type, value, prop)
129
+ end
130
+ end
131
+ end
132
+
133
+ def call_with_path(args)
134
+ if args.length == 2
135
+ get_by_path(args[0], json_body) do |json_chunk|
136
+ yield(args[1], json_chunk)
137
+ end
138
+ else
139
+ yield(args[0], json_body)
140
+ end
141
+ end
142
+
143
+ def extract_expected_value(expected, prop)
144
+ begin
145
+ raise unless expected.keys.include?(prop)
146
+ expected[prop]
147
+ rescue
148
+ raise ExpectationError, "Expectation is expected to contain property: #{prop}"
149
+ end
150
+ end
151
+
152
+ def extract_expected_type(expected, prop)
153
+ begin
154
+ type = expected[prop]
155
+ type.nil? ? raise : type
156
+ rescue
157
+ raise ExpectationError, "Expectation is expected to contain property: #{prop}"
158
+ end
159
+ end
160
+
161
+ def extract_actual(actual, prop)
162
+ begin
163
+ value = actual[prop]
164
+ rescue
165
+ raise ExpectationError, "Expected #{actual.class} #{actual}\nto be an object with property #{prop}"
166
+ end
167
+ end
168
+
169
+ def expect_type(expected_type, value, prop_name = nil)
170
+ fail ExpectationError, "Expected type #{expected_type}\nis an invalid type" if @mapper[expected_type].nil?
171
+
172
+ insert = prop_name.nil? ? '' : "#{prop_name} to be of type"
173
+ message = "Expected #{insert} #{expected_type}\n got #{value.class} instead"
174
+
175
+ expect(@mapper[expected_type].any?{|type| value.is_a?(type)}).to eq(true), message
176
+ end
177
+
178
+ def convert_to_date(value)
179
+ begin
180
+ DateTime.parse(value)
181
+ rescue
182
+ end
183
+ end
184
+
185
+ def check_array_types(value, prop_name, expected_type)
186
+ expect_array(value, prop_name, expected_type)
187
+ value.each do |val|
188
+ expect_type(expected_type, val, prop_name)
189
+ end
190
+ end
191
+
192
+ def nil_optional_hash?(expected, hash)
193
+ expected.is_a?(Airborne::OptionalHashTypeExpectations) && hash.nil?
194
+ end
195
+
196
+ def hash?(hash)
197
+ hash.is_a?(Hash) || hash.is_a?(Airborne::OptionalHashTypeExpectations)
198
+ end
199
+
200
+ def expect_array(value, prop_name, expected_type)
201
+ expect(value.class).to eq(Array), "Expected #{prop_name}\n to be of type #{expected_type}\n got #{value.class} instead"
202
+ end
203
+
204
+ def convert_expectations_for_json_sizes(old_expectations)
205
+ unless old_expectations.is_a?(Hash)
206
+ return convert_expectation_for_json_sizes(old_expectations)
207
+ end
208
+
209
+ old_expectations.each_with_object({}) do |(prop_name, expected_size), memo|
210
+ new_value = if expected_size.is_a?(Hash)
211
+ convert_expectations_for_json_sizes(expected_size)
212
+ else
213
+ convert_expectation_for_json_sizes(expected_size)
214
+ end
215
+ memo[prop_name] = new_value
216
+ end
217
+ end
218
+
219
+ def convert_expectation_for_json_sizes(expected_size)
220
+ ->(data) { expect(data.size).to eq(expected_size) }
221
+ end
222
+
223
+ def ensure_hash_contains_prop(prop_name, hash)
224
+ begin
225
+ yield
226
+ rescue
227
+ raise ExpectationError, "Expected #{hash.class} #{hash}\nto be an object with property #{prop_name}"
228
+ end
229
+ end
230
+
231
+ def property?(expectation)
232
+ [String, Regexp, Float, Integer, TrueClass, FalseClass, NilClass, Array].any?{|type| expectation.is_a?(type)}
233
+ end
234
+
235
+ def get_mapper
236
+ base_mapper = {
237
+ integer: [Integer],
238
+ array_of_integers: [Integer],
239
+ int: [Integer],
240
+ array_of_ints: [Integer],
241
+ float: [Float, Integer],
242
+ array_of_floats: [Float, Integer],
243
+ string: [String],
244
+ array_of_strings: [String],
245
+ boolean: [TrueClass, FalseClass],
246
+ array_of_booleans: [TrueClass, FalseClass],
247
+ bool: [TrueClass, FalseClass],
248
+ array_of_bools: [TrueClass, FalseClass],
249
+ object: [Hash],
250
+ array_of_objects: [Hash],
251
+ array: [Array],
252
+ array_of_arrays: [Array],
253
+ date: [DateTime],
254
+ null: [NilClass]
255
+ }
256
+
257
+ mapper = base_mapper.clone
258
+ base_mapper.each do |key, value|
259
+ mapper[(key.to_s + '_or_null').to_sym] = value + [NilClass]
260
+ end
261
+ mapper
262
+ end
263
+
264
+ def resolve_status(candidate, authority)
265
+ candidate = Rack::Utils::SYMBOL_TO_STATUS_CODE[candidate] if candidate.is_a?(Symbol)
266
+ case authority
267
+ when String then candidate.to_s
268
+ when Integer then candidate.to_i
269
+ else candidate
270
+ end
271
+ end
272
+
273
+ def match_none?
274
+ !match_actual? && !match_expected?
275
+ end
276
+
277
+ def match_actual?
278
+ Airborne.configuration.match_actual?
279
+ end
280
+
281
+ def match_expected?
282
+ Airborne.configuration.match_expected?
283
+ end
284
+ end
285
+ end
@@ -0,0 +1,33 @@
1
+ require 'rest_client'
2
+
3
+ module Airborne
4
+ module RestClientRequester
5
+ def make_request(method, url, options = {})
6
+ headers = base_headers.merge(options[:headers] || {})
7
+ res = if method == :post || method == :patch || method == :put
8
+ begin
9
+ request_body = options[:body].nil? ? '' : options[:body]
10
+ request_body = request_body.to_json if options[:body].is_a?(Hash)
11
+ RestClient::Request.execute(:method => method, :url => get_url(url), :payload => request_body,
12
+ :headers => headers , :verify_ssl => Airborne.configuration.verify_ssl)
13
+ rescue RestClient::Exception => e
14
+ e.response
15
+ end
16
+ else
17
+ begin
18
+ RestClient::Request.execute(:method => method, :url => get_url(url), :headers => headers,
19
+ :verify_ssl => Airborne.configuration.verify_ssl)
20
+ rescue RestClient::Exception => e
21
+ e.response
22
+ end
23
+ end
24
+ res
25
+ end
26
+
27
+ private
28
+
29
+ def base_headers
30
+ { content_type: :json }.merge(Airborne.configuration.headers || {})
31
+ end
32
+ end
33
+ end
data/lib/airborne.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'airborne/optional_hash_type_expectations'
2
+ require 'airborne/path_matcher'
3
+ require 'airborne/request_expectations'
4
+ require 'airborne/rest_client_requester'
5
+ require 'airborne/rack_test_requester'
6
+ require 'airborne/base'
7
+ require 'openssl'
8
+
9
+ RSpec.configure do |config|
10
+ config.add_setting :base_url
11
+ config.add_setting :verify_ssl, default: OpenSSL::SSL::VERIFY_NONE
12
+ config.add_setting :match_expected
13
+ config.add_setting :match_actual
14
+ config.add_setting :match_expected_default, default: true
15
+ config.add_setting :match_actual_default, default: false
16
+ config.add_setting :headers
17
+ config.add_setting :rack_app
18
+ config.add_setting :requester_type
19
+ config.add_setting :requester_module
20
+ config.before do |example|
21
+ config.match_expected = example.metadata[:match_expected].nil? ?
22
+ Airborne.configuration.match_expected_default? : example.metadata[:match_expected]
23
+ config.match_actual = example.metadata[:match_actual].nil? ?
24
+ Airborne.configuration.match_actual_default? : example.metadata[:match_actual]
25
+ end
26
+
27
+ # Include last since it depends on the configuration already being added
28
+ config.include Airborne
29
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'base spec' do
4
+ it 'when request is made response should be set' do
5
+ mock_get('simple_get')
6
+ get '/simple_get'
7
+ expect(response).to_not be(nil)
8
+ end
9
+
10
+ it 'when request is made headers should be set' do
11
+ mock_get('simple_get')
12
+ get '/simple_get'
13
+ expect(headers).to_not be(nil)
14
+ end
15
+
16
+ it 'should throw an InvalidJsonError when accessing json_body on invalid json' do
17
+ mock_get('invalid_json')
18
+ get '/invalid_json'
19
+ expect(body).to eq('invalid1234')
20
+ expect { json_body }.to raise_error(InvalidJsonError)
21
+ end
22
+
23
+ it 'when request is made headers should be hash with indifferent access' do
24
+ mock_get('simple_get', 'Content-Type' => 'application/json')
25
+ get '/simple_get'
26
+ expect(headers).to be_kind_of(Hash)
27
+ expect(headers[:content_type]).to eq('application/json')
28
+ expect(headers['content_type']).to eq('application/json')
29
+ end
30
+
31
+ it 'when request is made body should be set' do
32
+ mock_get('simple_get')
33
+ get '/simple_get'
34
+ expect(body).to_not be(nil)
35
+ end
36
+
37
+ it 'when request is made json body should be symbolized hash' do
38
+ mock_get('simple_get')
39
+ get '/simple_get'
40
+ expect(json_body).to be_kind_of(Hash)
41
+ expect(json_body.first[0]).to be_kind_of(Symbol)
42
+ end
43
+
44
+ it 'should handle a 500 error on get' do
45
+ mock_get('simple_get', {}, [500, 'Internal Server Error'])
46
+ get '/simple_get'
47
+ expect(json_body).to_not be(nil)
48
+ end
49
+
50
+ it 'should handle a 500 error on post' do
51
+ mock_post('simple_post', {}, [500, 'Internal Server Error'])
52
+ post '/simple_post', {}
53
+ expect(json_body).to_not be(nil)
54
+ end
55
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'openssl'
3
+
4
+ describe 'client requester' do
5
+ before do
6
+ allow(RestClient::Request).to receive(:execute)
7
+ RSpec::Mocks.space.proxy_for(self).remove_stub_if_present(:get)
8
+ end
9
+
10
+ after do
11
+ allow(RestClient).to receive(:send).and_call_original
12
+ Airborne.configure { |config| config.headers = {} }
13
+ end
14
+
15
+ it 'should set :content_type to :json by default' do
16
+ get '/foo'
17
+
18
+ expect(RestClient::Request).to have_received(:execute)
19
+ .with(:method => :get, :url => 'http://www.example.com/foo',
20
+ :headers => { content_type: :json }, :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
21
+ end
22
+
23
+ it 'should override headers with option[:headers]' do
24
+ get '/foo', { content_type: 'application/x-www-form-urlencoded' }
25
+
26
+ expect(RestClient::Request).to have_received(:execute)
27
+ .with(:method => :get, :url => 'http://www.example.com/foo',
28
+ :headers => { content_type: 'application/x-www-form-urlencoded' },
29
+ :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
30
+ end
31
+
32
+ it 'should override headers with airborne config headers' do
33
+ Airborne.configure { |config| config.headers = { content_type: 'text/plain' } }
34
+
35
+ get '/foo'
36
+
37
+ expect(RestClient::Request).to have_received(:execute)
38
+ .with(:method => :get, :url => 'http://www.example.com/foo',
39
+ :headers => { content_type: 'text/plain' },
40
+ :verify_ssl => OpenSSL::SSL::VERIFY_NONE)
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'delete' do
4
+ it 'should allow testing on delete requests' do
5
+ mock_delete 'simple_delete'
6
+ delete '/simple_delete', {}
7
+ expect_status 200
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'expect header contains' do
4
+ it 'should ensure partial header match exists' do
5
+ mock_get('simple_get', 'Content-Type' => 'application/json')
6
+ get '/simple_get'
7
+ expect_header_contains(:content_type, 'json')
8
+ end
9
+
10
+ it 'should ensure header is present' do
11
+ mock_get('simple_get', 'Content-Type' => 'application/json')
12
+ get '/simple_get'
13
+ expect { expect_header_contains(:foo, 'bar') }.to raise_error(ExpectationNotMetError)
14
+ end
15
+
16
+ it 'should ensure partial header is present' do
17
+ mock_get('simple_get', 'Content-Type' => 'application/json')
18
+ get '/simple_get'
19
+ expect { expect_header_contains(:content_type, 'bar') }.to raise_error(ExpectationNotMetError)
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'expect header' do
4
+ it 'should find exact match for header content' do
5
+ mock_get('simple_get', 'Content-Type' => 'application/json')
6
+ get '/simple_get'
7
+ expect_header(:content_type, 'application/json')
8
+ end
9
+
10
+ it 'should find exact match for header content' do
11
+ mock_get('simple_get', 'Content-Type' => 'json')
12
+ get '/simple_get'
13
+ expect { expect_header(:content_type, 'application/json') }.to raise_error(ExpectationNotMetError)
14
+ end
15
+
16
+ it 'should ensure correct headers are present' do
17
+ mock_get('simple_get', 'Content-Type' => 'application/json')
18
+ get '/simple_get'
19
+ expect { expect_header(:foo, 'bar') }.to raise_error(ExpectationNotMetError)
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'expect_json_keys with path' do
4
+ it 'should ensure json keys with path' do
5
+ mock_get('simple_nested_path')
6
+ get '/simple_nested_path', {}
7
+ expect_json_keys('address', [:street, :city])
8
+ end
9
+
10
+ it 'should fail when keys are missing with path' do
11
+ mock_get('simple_nested_path')
12
+ get '/simple_nested_path', {}
13
+ expect { expect_json_keys('address', [:bad]) }.to raise_error(ExpectationNotMetError)
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'expect_json_keys' do
4
+ it 'should fail when json keys are missing' do
5
+ mock_get('simple_json')
6
+ get '/simple_json', {}
7
+ expect { expect_json_keys([:foo, :bar, :baz, :bax]) }.to raise_error(ExpectationNotMetError)
8
+ end
9
+
10
+ it 'should ensure correct json keys' do
11
+ mock_get('simple_json')
12
+ get '/simple_json', {}
13
+ expect_json_keys([:foo, :bar, :baz])
14
+ end
15
+
16
+ it 'should ensure correct partial json keys' do
17
+ mock_get('simple_json')
18
+ get '/simple_json', {}
19
+ expect_json_keys([:foo, :bar])
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'expect_json lambda' do
4
+ it 'should invoke proc passed in' do
5
+ mock_get('simple_get')
6
+ get '/simple_get'
7
+ expect_json(name: ->(name) { expect(name.length).to eq(4) })
8
+ end
9
+ end