restspec 0.0.1

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 (202) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +21 -0
  3. data/.gitignore +23 -0
  4. data/.rspec +4 -0
  5. data/Gemfile +4 -0
  6. data/Guardfile +6 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +188 -0
  9. data/ROADMAP.md +11 -0
  10. data/Rakefile +20 -0
  11. data/bin/restspec +54 -0
  12. data/bin/templates/Gemfile +3 -0
  13. data/bin/templates/custom_macros.rb +3 -0
  14. data/bin/templates/restspec_config.rb +10 -0
  15. data/bin/templates/spec_helper.rb +19 -0
  16. data/docs/endpoints.md +200 -0
  17. data/docs/helpers.md +40 -0
  18. data/docs/macros.md +140 -0
  19. data/docs/matchers.md +38 -0
  20. data/docs/schemas.md +28 -0
  21. data/docs/tutorial.md +477 -0
  22. data/docs/types.md +134 -0
  23. data/examples/store-api-tests/.rspec +3 -0
  24. data/examples/store-api-tests/Gemfile +4 -0
  25. data/examples/store-api-tests/Gemfile.lock +70 -0
  26. data/examples/store-api-tests/spec/api/category_spec.rb +23 -0
  27. data/examples/store-api-tests/spec/api/product_spec.rb +55 -0
  28. data/examples/store-api-tests/spec/api/restspec/endpoints.rb +39 -0
  29. data/examples/store-api-tests/spec/api/restspec/requirements.rb +0 -0
  30. data/examples/store-api-tests/spec/api/restspec/restspec_config.rb +6 -0
  31. data/examples/store-api-tests/spec/api/restspec/schemas.rb +11 -0
  32. data/examples/store-api-tests/spec/spec_helper.rb +19 -0
  33. data/examples/store-api-tests/spec/support/custom_macros.rb +3 -0
  34. data/examples/store-api-tests/spec/support/custom_matchers.rb +0 -0
  35. data/examples/store-api/.editorconfig +24 -0
  36. data/examples/store-api/.rbenv-vars.example +3 -0
  37. data/examples/store-api/.rspec +4 -0
  38. data/examples/store-api/.ruby-version +1 -0
  39. data/examples/store-api/Gemfile +58 -0
  40. data/examples/store-api/Gemfile.lock +216 -0
  41. data/examples/store-api/Guardfile +39 -0
  42. data/examples/store-api/README.md +1 -0
  43. data/examples/store-api/Rakefile +6 -0
  44. data/examples/store-api/app/assets/images/.keep +0 -0
  45. data/examples/store-api/app/assets/javascripts/application.js +16 -0
  46. data/examples/store-api/app/assets/javascripts/categories.js.coffee +3 -0
  47. data/examples/store-api/app/assets/javascripts/products.js.coffee +3 -0
  48. data/examples/store-api/app/assets/stylesheets/application.css +15 -0
  49. data/examples/store-api/app/assets/stylesheets/categories.css.scss +3 -0
  50. data/examples/store-api/app/assets/stylesheets/products.css.scss +3 -0
  51. data/examples/store-api/app/assets/stylesheets/scaffolds.css.scss +69 -0
  52. data/examples/store-api/app/controllers/application_controller.rb +5 -0
  53. data/examples/store-api/app/controllers/categories_controller.rb +74 -0
  54. data/examples/store-api/app/controllers/concerns/.keep +0 -0
  55. data/examples/store-api/app/controllers/products_controller.rb +74 -0
  56. data/examples/store-api/app/helpers/application_helper.rb +2 -0
  57. data/examples/store-api/app/helpers/categories_helper.rb +2 -0
  58. data/examples/store-api/app/helpers/products_helper.rb +2 -0
  59. data/examples/store-api/app/mailers/.keep +0 -0
  60. data/examples/store-api/app/models/.keep +0 -0
  61. data/examples/store-api/app/models/category.rb +2 -0
  62. data/examples/store-api/app/models/concerns/.keep +0 -0
  63. data/examples/store-api/app/models/product.rb +3 -0
  64. data/examples/store-api/app/views/categories/_form.html.erb +21 -0
  65. data/examples/store-api/app/views/categories/edit.html.erb +6 -0
  66. data/examples/store-api/app/views/categories/index.html.erb +25 -0
  67. data/examples/store-api/app/views/categories/index.json.jbuilder +4 -0
  68. data/examples/store-api/app/views/categories/new.html.erb +5 -0
  69. data/examples/store-api/app/views/categories/show.html.erb +9 -0
  70. data/examples/store-api/app/views/categories/show.json.jbuilder +1 -0
  71. data/examples/store-api/app/views/layouts/application.html.erb +14 -0
  72. data/examples/store-api/app/views/products/_form.html.erb +29 -0
  73. data/examples/store-api/app/views/products/edit.html.erb +6 -0
  74. data/examples/store-api/app/views/products/index.html.erb +29 -0
  75. data/examples/store-api/app/views/products/index.json.jbuilder +4 -0
  76. data/examples/store-api/app/views/products/new.html.erb +5 -0
  77. data/examples/store-api/app/views/products/show.html.erb +19 -0
  78. data/examples/store-api/app/views/products/show.json.jbuilder +6 -0
  79. data/examples/store-api/bin/bundle +3 -0
  80. data/examples/store-api/bin/guard +16 -0
  81. data/examples/store-api/bin/rails +8 -0
  82. data/examples/store-api/bin/rake +8 -0
  83. data/examples/store-api/bin/spring +18 -0
  84. data/examples/store-api/config.ru +4 -0
  85. data/examples/store-api/config/application.rb +30 -0
  86. data/examples/store-api/config/boot.rb +4 -0
  87. data/examples/store-api/config/database.yml +25 -0
  88. data/examples/store-api/config/environment.rb +5 -0
  89. data/examples/store-api/config/environments/development.rb +37 -0
  90. data/examples/store-api/config/environments/production.rb +78 -0
  91. data/examples/store-api/config/environments/test.rb +39 -0
  92. data/examples/store-api/config/initializers/assets.rb +8 -0
  93. data/examples/store-api/config/initializers/backtrace_silencers.rb +7 -0
  94. data/examples/store-api/config/initializers/cookies_serializer.rb +3 -0
  95. data/examples/store-api/config/initializers/filter_parameter_logging.rb +4 -0
  96. data/examples/store-api/config/initializers/inflections.rb +16 -0
  97. data/examples/store-api/config/initializers/mime_types.rb +4 -0
  98. data/examples/store-api/config/initializers/session_store.rb +3 -0
  99. data/examples/store-api/config/initializers/wrap_parameters.rb +14 -0
  100. data/examples/store-api/config/locales/en.yml +23 -0
  101. data/examples/store-api/config/routes.rb +59 -0
  102. data/examples/store-api/config/secrets.yml +22 -0
  103. data/examples/store-api/db/migrate/20141205154816_create_products.rb +11 -0
  104. data/examples/store-api/db/migrate/20141205171104_create_categories.rb +9 -0
  105. data/examples/store-api/db/migrate/20141205171140_add_category_id_to_products.rb +5 -0
  106. data/examples/store-api/db/schema.rb +31 -0
  107. data/examples/store-api/db/seeds.rb +7 -0
  108. data/examples/store-api/lib/assets/.keep +0 -0
  109. data/examples/store-api/lib/tasks/.keep +0 -0
  110. data/examples/store-api/log/.keep +0 -0
  111. data/examples/store-api/public/404.html +67 -0
  112. data/examples/store-api/public/422.html +67 -0
  113. data/examples/store-api/public/500.html +66 -0
  114. data/examples/store-api/public/favicon.ico +0 -0
  115. data/examples/store-api/public/robots.txt +5 -0
  116. data/examples/store-api/spec/controllers/categories_controller_spec.rb +159 -0
  117. data/examples/store-api/spec/controllers/products_controller_spec.rb +159 -0
  118. data/examples/store-api/spec/factories/categories.rb +6 -0
  119. data/examples/store-api/spec/factories/products.rb +8 -0
  120. data/examples/store-api/spec/helpers/categories_helper_spec.rb +15 -0
  121. data/examples/store-api/spec/helpers/products_helper_spec.rb +15 -0
  122. data/examples/store-api/spec/models/category_spec.rb +5 -0
  123. data/examples/store-api/spec/models/product_spec.rb +5 -0
  124. data/examples/store-api/spec/rails_helper.rb +50 -0
  125. data/examples/store-api/spec/requests/categories_spec.rb +10 -0
  126. data/examples/store-api/spec/requests/products_spec.rb +10 -0
  127. data/examples/store-api/spec/routing/categories_routing_spec.rb +35 -0
  128. data/examples/store-api/spec/routing/products_routing_spec.rb +35 -0
  129. data/examples/store-api/spec/spec_helper.rb +85 -0
  130. data/examples/store-api/spec/views/categories/edit.html.erb_spec.rb +18 -0
  131. data/examples/store-api/spec/views/categories/index.html.erb_spec.rb +19 -0
  132. data/examples/store-api/spec/views/categories/new.html.erb_spec.rb +18 -0
  133. data/examples/store-api/spec/views/categories/show.html.erb_spec.rb +14 -0
  134. data/examples/store-api/spec/views/products/edit.html.erb_spec.rb +24 -0
  135. data/examples/store-api/spec/views/products/index.html.erb_spec.rb +25 -0
  136. data/examples/store-api/spec/views/products/new.html.erb_spec.rb +24 -0
  137. data/examples/store-api/spec/views/products/show.html.erb_spec.rb +18 -0
  138. data/examples/store-api/vendor/assets/javascripts/.keep +0 -0
  139. data/examples/store-api/vendor/assets/stylesheets/.keep +0 -0
  140. data/lib/restspec.rb +38 -0
  141. data/lib/restspec/configuration.rb +43 -0
  142. data/lib/restspec/endpoints/dsl.rb +142 -0
  143. data/lib/restspec/endpoints/endpoint.rb +135 -0
  144. data/lib/restspec/endpoints/namespace.rb +89 -0
  145. data/lib/restspec/endpoints/network.rb +39 -0
  146. data/lib/restspec/endpoints/request.rb +11 -0
  147. data/lib/restspec/endpoints/response.rb +53 -0
  148. data/lib/restspec/requirements/dsl.rb +10 -0
  149. data/lib/restspec/requirements/requirement.rb +59 -0
  150. data/lib/restspec/rspec/api_helpers.rb +64 -0
  151. data/lib/restspec/rspec/api_macros.rb +126 -0
  152. data/lib/restspec/rspec/extras.rb +2 -0
  153. data/lib/restspec/rspec/matchers/api_matchers.rb +6 -0
  154. data/lib/restspec/rspec/matchers/be_like_schema.rb +18 -0
  155. data/lib/restspec/rspec/matchers/be_like_schema_array.rb +18 -0
  156. data/lib/restspec/rspec/matchers/have_header.rb +47 -0
  157. data/lib/restspec/rspec/matchers/have_status.rb +17 -0
  158. data/lib/restspec/rspec/matchers/include_where.rb +14 -0
  159. data/lib/restspec/rspec/shared_examples.rb +12 -0
  160. data/lib/restspec/schema/attribute.rb +31 -0
  161. data/lib/restspec/schema/attribute_example.rb +21 -0
  162. data/lib/restspec/schema/checker.rb +73 -0
  163. data/lib/restspec/schema/dsl.rb +36 -0
  164. data/lib/restspec/schema/schema.rb +21 -0
  165. data/lib/restspec/schema/schema_example.rb +28 -0
  166. data/lib/restspec/schema/types.rb +35 -0
  167. data/lib/restspec/schema/types/array_type.rb +34 -0
  168. data/lib/restspec/schema/types/basic_type.rb +35 -0
  169. data/lib/restspec/schema/types/boolean_type.rb +11 -0
  170. data/lib/restspec/schema/types/decimal_string_type.rb +32 -0
  171. data/lib/restspec/schema/types/decimal_type.rb +14 -0
  172. data/lib/restspec/schema/types/embedded_schema_type.rb +28 -0
  173. data/lib/restspec/schema/types/hash_type.rb +25 -0
  174. data/lib/restspec/schema/types/integer_type.rb +11 -0
  175. data/lib/restspec/schema/types/null_type.rb +11 -0
  176. data/lib/restspec/schema/types/one_of_type.rb +21 -0
  177. data/lib/restspec/schema/types/schema_id_type.rb +88 -0
  178. data/lib/restspec/schema/types/string_type.rb +11 -0
  179. data/lib/restspec/shortcuts.rb +8 -0
  180. data/lib/restspec/stores/endpoint_store.rb +25 -0
  181. data/lib/restspec/stores/namespace_store.rb +20 -0
  182. data/lib/restspec/stores/schema_store.rb +19 -0
  183. data/lib/restspec/values/status_code.rb +13 -0
  184. data/lib/restspec/values/super_hash.rb +12 -0
  185. data/lib/restspec/version.rb +3 -0
  186. data/restspec.gemspec +37 -0
  187. data/spec/restspec/endpoints/dsl_spec.rb +269 -0
  188. data/spec/restspec/endpoints/endpoint_spec.rb +146 -0
  189. data/spec/restspec/endpoints/namespace_spec.rb +143 -0
  190. data/spec/restspec/endpoints/response_spec.rb +49 -0
  191. data/spec/restspec/schema/attribute_example_spec.rb +35 -0
  192. data/spec/restspec/schema/dsl_spec.rb +78 -0
  193. data/spec/restspec/schema/schema_example_spec.rb +40 -0
  194. data/spec/restspec/schema/schema_spec.rb +11 -0
  195. data/spec/restspec/schema/types/array_type_spec.rb +56 -0
  196. data/spec/restspec/schema/types/basic_type_spec.rb +62 -0
  197. data/spec/restspec/schema/types/boolean_type_spec.rb +26 -0
  198. data/spec/restspec/schema/types/null_type_spec.rb +25 -0
  199. data/spec/restspec/schema/types/string_type_spec.rb +26 -0
  200. data/spec/restspec/values/status_code_spec.rb +13 -0
  201. data/spec/spec_helper.rb +23 -0
  202. metadata +484 -0
@@ -0,0 +1,39 @@
1
+ module Restspec
2
+ module Endpoints
3
+ module Network
4
+ extend self
5
+
6
+ def request(request_object)
7
+ code, headers, body = network_adapter.request(request_object)
8
+ Response.new(code, headers, body)
9
+ end
10
+
11
+ private
12
+
13
+ def network_adapter
14
+ network_adapter_lambda.try(:call) || default_network_adapter
15
+ end
16
+
17
+ def network_adapter_lambda
18
+ Restspec.config.request.network_adapter
19
+ end
20
+
21
+ def default_network_adapter
22
+ HTTPartyNetworkAdapter.new
23
+ end
24
+
25
+ class HTTPartyNetworkAdapter
26
+ def request(request_object)
27
+ response = HTTParty.send(
28
+ request_object.method,
29
+ request_object.url,
30
+ headers: request_object.headers,
31
+ body: request_object.raw_payload
32
+ )
33
+
34
+ [response.code, response.headers, response.body]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,11 @@
1
+ module Restspec
2
+ module Endpoints
3
+ class Request < Struct.new(:method, :url, :headers, :payload)
4
+ attr_accessor :endpoint
5
+
6
+ def raw_payload
7
+ @raw_payload ||= (payload || '').to_json
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,53 @@
1
+ require 'delegate'
2
+
3
+ module Restspec
4
+ module Endpoints
5
+ class Response
6
+ attr_accessor :endpoint, :headers, :code, :raw_body
7
+
8
+ def initialize(code, headers, raw_body)
9
+ self.headers = headers
10
+ self.code = code
11
+ self.raw_body = raw_body
12
+ end
13
+
14
+ def to_s
15
+ if endpoint.present?
16
+ url = endpoint.executed_url || endpoint.full_path
17
+ "[#{endpoint.method.upcase} to #{url}]"
18
+ else
19
+ raw_body
20
+ end
21
+ end
22
+
23
+ def read_body(value = parsed_body)
24
+ case value
25
+ when Array
26
+ value.map { |item| read_body(item) }
27
+ when Hash
28
+ Values::SuperHash.new(value).tap do |super_hash|
29
+ super_hash.find do |key, value|
30
+ if value.class == Array
31
+ super_hash[key] = read_body(value)
32
+ end
33
+ end
34
+ end
35
+ else
36
+ value
37
+ end
38
+ end
39
+
40
+ def parsed_body
41
+ @parsed_body ||= begin
42
+ JSON.parse(raw_body)
43
+ rescue JSON::ParserError => e
44
+ raw_body
45
+ end
46
+ end
47
+
48
+ def body
49
+ @body ||= read_body
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,10 @@
1
+ module Restspec
2
+ module Requirements
3
+ class DSL
4
+ def requirement(name, &definition)
5
+ requirement = Requirement.get_or_create(name)
6
+ requirement.instance_eval(&definition)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,59 @@
1
+ module Restspec
2
+ module Requirements
3
+ class Requirement
4
+ attr_reader :name, :errors
5
+
6
+ def initialize(name)
7
+ self.name = name
8
+ self.errors = []
9
+ extend Restspec::RSpec::ApiHelpers
10
+ end
11
+
12
+ def execution(&execution_block)
13
+ define_singleton_method(:execute, &execution_block)
14
+ end
15
+
16
+ def execute
17
+ end
18
+
19
+ def assert!
20
+ execute
21
+ if errors.any?
22
+ raise errors.join(' | ')
23
+ end
24
+ end
25
+
26
+ def add_error(error)
27
+ errors << error
28
+ end
29
+
30
+ private
31
+
32
+ attr_writer :name, :errors
33
+
34
+ class << self
35
+ attr_reader :requirements
36
+
37
+ def get_or_create(name)
38
+ find_by_name(name) || create(name)
39
+ end
40
+
41
+ def find_by_name(name)
42
+ requirements.find { |r| r.name == name }
43
+ end
44
+
45
+ def create(name)
46
+ self.new(name).tap { |r| requirements << r }
47
+ end
48
+
49
+ def requirements
50
+ @requirements ||= []
51
+ end
52
+
53
+ private
54
+
55
+ attr_writer :requirements
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,64 @@
1
+ require 'active_support/core_ext/object'
2
+
3
+ module Restspec
4
+ module RSpec
5
+ module ApiHelpers
6
+ def read_endpoint(endpoint_full_name = nil, options = {})
7
+ call_endpoint(endpoint_full_name, options).read_body
8
+ end
9
+
10
+ def call_endpoint(endpoint_full_name = nil, body: {},
11
+ url_params: {},
12
+ query_params: {},
13
+ merge_example_params: true,
14
+ execution_method: :execute)
15
+ endpoint = find_endpoint_in_test_context(endpoint_full_name)
16
+
17
+ if merge_example_params
18
+ query_params = (@query_params || {}).merge(query_params)
19
+ url_params = (@url_params || {}).merge(url_params)
20
+ end
21
+
22
+ endpoint.send(execution_method, body: body, url_params: url_params, query_params: query_params)
23
+ end
24
+
25
+ def find_endpoint_in_test_context(endpoint_full_name)
26
+ if endpoint_full_name.present?
27
+ test_context = self.class
28
+
29
+ test_context.metadata[:endpoints] ||= {}
30
+ test_context.metadata[:endpoints][endpoint_full_name] ||= begin
31
+ Restspec::EndpointStore.get(endpoint_full_name)
32
+ end
33
+ else
34
+ endpoint
35
+ end
36
+ end
37
+
38
+ def read_endpoint_once(endpoint_full_name = nil, options = {})
39
+ call_endpoint_once(endpoint_full_name, options).read_body
40
+ end
41
+
42
+ def call_endpoint_once(endpoint_full_name = nil, options = {})
43
+ call_endpoint(endpoint_full_name, options.merge(:execution_method => :execute_once))
44
+ end
45
+
46
+ def execute_endpoint!
47
+ execute_endpoint_lambda.call
48
+ response
49
+ end
50
+
51
+ def schema_example(schema_name = nil)
52
+ if schema_name.nil? && endpoint.present?
53
+ schema_name = endpoint.schema_name
54
+ end
55
+
56
+ Restspec.example_for(schema_name)
57
+ end
58
+
59
+ def self.included(base)
60
+ base.extend(self)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,126 @@
1
+ require_relative './matchers/api_matchers'
2
+
3
+ module Restspec
4
+ module RSpec
5
+ module ApiMacros
6
+ def endpoint(name, options = {}, &block)
7
+ endpoint = Restspec::EndpointStore.get(name).dup
8
+
9
+ implicit_test = options[:implicit_test]
10
+
11
+ self.metadata[:current_endpoint_template] = endpoint
12
+ self.metadata[:resource_endpoint] = Restspec::EndpointStore.get(options[:resource])
13
+
14
+ describe "[#{endpoint.method.to_s.upcase} #{endpoint.name}]", options do
15
+ implicit_test ? test(&block) : instance_eval(&block)
16
+ end
17
+ end
18
+
19
+ def test(message = 'the happy path', options = {}, &test_body)
20
+ endpoint_context = self
21
+ endpoint_context.metadata[:before_callbacks] = []
22
+
23
+ context(message, options) do
24
+ test_context = self
25
+
26
+ let(:endpoint) do
27
+ endpoint_block_endpoint = endpoint_context.metadata[:current_endpoint_template]
28
+ test_context.metadata[:current_endpoint] ||= endpoint_block_endpoint.clone
29
+ end
30
+
31
+ before { response }
32
+
33
+ let(:response) do
34
+ @response = execute_endpoint_lambda.call
35
+ end
36
+
37
+ let(:request) do
38
+ endpoint.last_request
39
+ end
40
+
41
+ let(:resource_endpoint) do
42
+ test_context.metadata[:resource_endpoint]
43
+ end
44
+
45
+ let(:initial_resource) do
46
+ test_context.metadata[:initial_resource] ||= begin
47
+ resource_endpoint.try(:execute).try(:body)
48
+ end
49
+ end
50
+
51
+ let(:final_resource) { body }
52
+
53
+ let(:execute_endpoint_lambda) do
54
+ resource_params = resource_endpoint.try(:url_params) || {}
55
+ before_callbacks = test_context.metadata[:before_callbacks]
56
+
57
+ -> do
58
+ endpoint.execute_once(
59
+ body: payload.merge(@payload || {}),
60
+ url_params: url_params.merge(resource_params).merge(@url_params || {}),
61
+ query_params: query_params.merge(@query_params || {}),
62
+ before: ->do
63
+ before_callbacks.each { |callback| instance_eval(&callback) }
64
+ initial_resource
65
+ end
66
+ )
67
+ end
68
+ end
69
+
70
+ let(:body) { response.body }
71
+
72
+ subject { response }
73
+
74
+ let(:payload) do
75
+ defined?(example_payload) ? example_payload : {}
76
+ end
77
+
78
+ let(:url_params) do
79
+ defined?(example_url_params) ? example_url_params : {}
80
+ end
81
+
82
+ let(:query_params) do
83
+ defined?(example_query_params) ? example_query_params : {}
84
+ end
85
+
86
+ instance_eval(&test_body)
87
+ end
88
+ end
89
+
90
+ def before_test(&block)
91
+ metadata[:before_callbacks] << block
92
+ end
93
+
94
+ def payload(params = {}, &payload_block)
95
+ let(:example_payload) do
96
+ payload_params = payload_block.present? ? instance_eval(&payload_block) : {}
97
+ Restspec::Values::SuperHash.new(params.merge(payload_params))
98
+ end
99
+ end
100
+
101
+ def url_params(params = nil, &params_block)
102
+ let(:example_url_params) do
103
+ Restspec::Values::SuperHash.new(params || instance_eval(&params_block))
104
+ end
105
+ end
106
+
107
+ def query_params(params = nil, &params_block)
108
+ let(:example_query_params) do
109
+ Restspec::Values::SuperHash.new(params || instance_eval(&params_block))
110
+ end
111
+ end
112
+
113
+ def ensure!(name)
114
+ requirement = Restspec::Requirements::Requirement.find_by_name(name)
115
+ requirement.assert!
116
+ end
117
+
118
+ def within_response(&block)
119
+ context 'within response' do
120
+ subject { response.body }
121
+ instance_eval(&block)
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,2 @@
1
+ require 'rspec/its'
2
+ require 'rspec/collection_matchers'
@@ -0,0 +1,6 @@
1
+ require 'rspec/expectations'
2
+ require_relative './have_status'
3
+ require_relative './have_header'
4
+ require_relative './be_like_schema'
5
+ require_relative './be_like_schema_array'
6
+ require_relative './include_where'
@@ -0,0 +1,18 @@
1
+ RSpec::Matchers.define :be_like_schema do |schema_name = nil|
2
+ match do |response|
3
+ schema = if schema_name.present?
4
+ Restspec::SchemaStore.get(schema_name)
5
+ else
6
+ response.endpoint.schema
7
+ end
8
+
9
+ body = response.respond_to?(:body) ? response.body : response
10
+ checker_for(schema).check!(body)
11
+ end
12
+
13
+ private
14
+
15
+ def checker_for(schema)
16
+ Restspec::Schema::Checker.new(schema)
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ RSpec::Matchers.define :be_like_schema_array do |schema_name = nil|
2
+ match do |response|
3
+ schema = if schema_name.present?
4
+ Restspec::SchemaStore.get(schema_name)
5
+ else
6
+ response.endpoint.schema
7
+ end
8
+
9
+ body = response.respond_to?(:body) ? response.body : response
10
+ checker_for(schema).check_array!(body)
11
+ end
12
+
13
+ private
14
+
15
+ def checker_for(schema)
16
+ Restspec::Schema::Checker.new(schema)
17
+ end
18
+ end
@@ -0,0 +1,47 @@
1
+ RSpec::Matchers.define :have_header do |key|
2
+ match do |response|
3
+ chained_test.perform(key, response.headers)
4
+ end
5
+
6
+ chain :equals do |expected_header_value|
7
+ @chained_test = Restspec::HeaderTests::EqualsTest.new(expected_header_value)
8
+ end
9
+
10
+ chain :that_contains do |expected_header_part|
11
+ @chained_test = Restspec::HeaderTests::ContainsTest.new(expected_header_part)
12
+ end
13
+
14
+ chain :that_matches do |expected_header_regex|
15
+ @chained_test = Restspec::HeaderTests::MatchesTest.new(expected_header_regex)
16
+ end
17
+
18
+ def chained_test
19
+ @chained_test ||= Restspec::HeaderTests::HaveKeyTest.new
20
+ end
21
+ end
22
+
23
+ module Restspec::HeaderTests
24
+ class HaveKeyTest
25
+ def perform(key, headers)
26
+ headers.has_key?(key)
27
+ end
28
+ end
29
+
30
+ class EqualsTest < Struct.new(:expected_header_value)
31
+ def perform(key, headers)
32
+ headers.fetch(key) == expected_header_value
33
+ end
34
+ end
35
+
36
+ class ContainsTest < Struct.new(:expected_header_part)
37
+ def perform(key, headers)
38
+ headers.fetch(key).include? expected_header_part
39
+ end
40
+ end
41
+
42
+ class MatchesTest < Struct.new(:expected_header_regex)
43
+ def perform(key, headers)
44
+ headers.fetch(key).match(expected_header_regex).present?
45
+ end
46
+ end
47
+ end