hops-airborne 0.2.15

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