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,25 @@
1
+ module Restspec::Schema::Types
2
+ class HashType < BasicType
3
+ def example_for(attribute)
4
+ {}
5
+ end
6
+
7
+ def valid?(attribute, value)
8
+ is_hash = value.is_a?(Hash)
9
+ keys = schema_options.fetch(:keys, [])
10
+
11
+ if keys.empty?
12
+ is_hash
13
+ else
14
+ value_type = schema_options.fetch(:value_type, nil)
15
+
16
+ is_hash && keys.all? do |key|
17
+ has_key = value.has_key?(key)
18
+ if has_key && value_type
19
+ has_key && value_type.totally_valid?(attribute, value[key])
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ module Restspec::Schema::Types
2
+ class IntegerType < BasicType
3
+ def example_for(attribute)
4
+ Faker::Number.digit
5
+ end
6
+
7
+ def valid?(attribute, value)
8
+ value.is_a?(Fixnum)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Restspec::Schema::Types
2
+ class NullType < BasicType
3
+ def example_for(attribute)
4
+ nil
5
+ end
6
+
7
+ def valid?(attribute, value)
8
+ value.nil?
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module Restspec::Schema::Types
2
+ class OneOfType < BasicType
3
+ def example_for(attribute)
4
+ elements.sample
5
+ end
6
+
7
+ def valid?(attribute, value)
8
+ elements.include?(value)
9
+ end
10
+
11
+ def to_s
12
+ "OneOfType(#{elements})"
13
+ end
14
+
15
+ private
16
+
17
+ def elements
18
+ options.fetch(:elements)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,88 @@
1
+ module Restspec::Schema::Types
2
+ class SchemaIdType < BasicType
3
+ attr_accessor :schema_name
4
+
5
+ def initialize(options, options_when_name_is_present = {})
6
+ if options.is_a?(Symbol)
7
+ self.schema_name = options
8
+ super(options_when_name_is_present)
9
+ else
10
+ super(options)
11
+ end
12
+ end
13
+
14
+ def example_for(attribute)
15
+ return sample_item.id if sample_item.present?
16
+
17
+ if create_response.code == 201 && create_response.body.try(:id)
18
+ create_response.body.id
19
+ else
20
+ example_options.fetch(:hardcoded_fallback) {
21
+ raise "We couldn't fetch any information for this example"
22
+ }
23
+ end
24
+ end
25
+
26
+ def valid?(attribute, value)
27
+ return true unless perform_validation?
28
+ item_ids.any? { |item| item.id == value }
29
+ end
30
+
31
+ private
32
+
33
+ def find_endpoint(name)
34
+ Restspec::EndpointStore.get(name)
35
+ end
36
+
37
+ def sample_item
38
+ @sample_item ||= get_sample_item
39
+ end
40
+
41
+ def get_index_endpoint
42
+ if schema_name.present?
43
+ Restspec::EndpointStore.get_by_schema_and_name(schema_name, :index)
44
+ else
45
+ find_endpoint(example_options.fetch(:fetch_endpoint))
46
+ end
47
+ end
48
+
49
+ def get_sample_item
50
+ fetch_endpoint = get_index_endpoint
51
+ fetch_endpoint.execute.body.try(:sample)
52
+ end
53
+
54
+ def create_response
55
+ create_endpoint.execute(body: create_example)
56
+ end
57
+
58
+ def get_create_endpoint
59
+ if schema_name.present?
60
+ namespace = Restspec::Endpoints::Namespace.get_by_schema_name(schema_name)
61
+ namespace.get_endpoint(:create)
62
+ else
63
+ find_endpoint(example_options.fetch(:create_endpoint))
64
+ end
65
+ end
66
+
67
+ def create_endpoint
68
+ @create_endpoint ||= get_create_endpoint
69
+ end
70
+
71
+ def create_example
72
+ Restspec.example_for(create_schema_name)
73
+ end
74
+
75
+ def create_schema_name
76
+ example_options.fetch(:create_schema, create_endpoint.schema_name)
77
+ end
78
+
79
+ def perform_validation?
80
+ schema_options.fetch(:perform_validation, true)
81
+ end
82
+
83
+ def item_ids
84
+ fetch_endpoint = get_index_endpoint
85
+ fetch_endpoint.execute.body
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,11 @@
1
+ module Restspec::Schema::Types
2
+ class StringType < BasicType
3
+ def example_for(attribute)
4
+ Faker::Lorem.word
5
+ end
6
+
7
+ def valid?(attribute, value)
8
+ value.is_a?(String)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ module Restspec
2
+ class << self
3
+ def example_for(schema_name, extensions = {})
4
+ schema = Restspec::SchemaStore.get(schema_name)
5
+ Schema::SchemaExample.new(schema, extensions).value
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,25 @@
1
+ require 'delegate'
2
+
3
+ module Restspec
4
+ module Stores
5
+ class EndpointStoreDelegator < SimpleDelegator
6
+ def store(endpoint)
7
+ self[endpoint.full_name] = endpoint
8
+ end
9
+
10
+ def get(endpoint_name)
11
+ self[endpoint_name]
12
+ end
13
+
14
+ def get_by_schema_and_name(schema_name, endpoint_name)
15
+ values.find do |endpoint|
16
+ endpoint.schema_name == schema_name && endpoint.name == endpoint_name
17
+ end
18
+ end
19
+ end
20
+
21
+ EndpointStore = EndpointStoreDelegator.new(Hash.new)
22
+ end
23
+
24
+ EndpointStore = Stores::EndpointStore
25
+ end
@@ -0,0 +1,20 @@
1
+ require 'delegate'
2
+
3
+ module Restspec
4
+ module Stores
5
+ class NamespaceStoreDelegator < SimpleDelegator
6
+ def store(namespace)
7
+ self << namespace
8
+ end
9
+
10
+ def get(namespace_name)
11
+ possible_names = [namespace_name.to_s, namespace_name.to_sym]
12
+ find { |ns| possible_names.include?(ns.name) }
13
+ end
14
+ end
15
+
16
+ NamespaceStore = NamespaceStoreDelegator.new(Array.new)
17
+ end
18
+
19
+ NamespaceStore = Stores::NamespaceStore
20
+ end
@@ -0,0 +1,19 @@
1
+ require 'delegate'
2
+
3
+ module Restspec
4
+ module Stores
5
+ class SchemaStoreDelegator < SimpleDelegator
6
+ def store(schema)
7
+ self[schema.name] = schema
8
+ end
9
+
10
+ def get(schema_name)
11
+ self[schema_name]
12
+ end
13
+ end
14
+
15
+ SchemaStore = SchemaStoreDelegator.new(Hash.new)
16
+ end
17
+
18
+ SchemaStore = Stores::SchemaStore
19
+ end
@@ -0,0 +1,13 @@
1
+ module Restspec
2
+ module Values
3
+ class StatusCode < Struct.new(:number_or_symbol)
4
+ def value
5
+ if number_or_symbol.is_a?(Symbol)
6
+ Rack::Utils::SYMBOL_TO_STATUS_CODE.fetch(number_or_symbol)
7
+ else
8
+ number_or_symbol
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ require 'hashie'
2
+
3
+ module Restspec
4
+ module Values
5
+ class SuperHash < Hash
6
+ include Hashie::Extensions::MethodAccess
7
+ include Hashie::Extensions::DeepMerge
8
+ include Hashie::Extensions::IndifferentAccess
9
+ include Hashie::Extensions::MergeInitializer
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module Restspec
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'restspec/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "restspec"
8
+ spec.version = Restspec::VERSION
9
+ spec.authors = ["juliogarciag"]
10
+ spec.email = ["julioggonz@gmail.com"]
11
+ spec.summary = %q{RSpec macros, helpers and matchers to work with APIs}
12
+ spec.description = %q{RSpec macros, helpers and matchers to work with APIs}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = ['restspec']
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "pry", "~> 0.10"
24
+ spec.add_development_dependency "guard", "~> 2.8"
25
+ spec.add_development_dependency "guard-rspec", "~> 4.3"
26
+ spec.add_development_dependency "rspec-nc", "~> 0.2"
27
+ spec.add_development_dependency "simplecov", "~> 0.9.1"
28
+ spec.add_dependency "activesupport", "~> 4.0"
29
+ spec.add_dependency "faker", "~> 1.4"
30
+ spec.add_dependency "hashie", "~> 3.3"
31
+ spec.add_dependency "rack", "~> 1.0"
32
+ spec.add_dependency "rspec", "~> 3.0"
33
+ spec.add_dependency "httparty", "~> 0.13"
34
+ spec.add_dependency "rspec-its", "~> 1.0"
35
+ spec.add_dependency "rspec-collection_matchers", "~> 1.0"
36
+ spec.add_dependency "thor", "~> 0.19"
37
+ end
@@ -0,0 +1,269 @@
1
+ require 'spec_helper'
2
+
3
+ describe Restspec::Endpoints::DSL do
4
+ let(:dsl) { Restspec::Endpoints::DSL.new }
5
+
6
+ before do
7
+ Restspec::NamespaceStore.clear
8
+ Restspec::EndpointStore.clear
9
+ end
10
+
11
+ describe '#namespace' do
12
+ it 'creates a namespace' do
13
+ expect do
14
+ dsl.namespace(:monkey) { }
15
+ end.to change { Restspec::NamespaceStore.size }.by(1)
16
+ end
17
+
18
+ it 'creates a namespace with the given name as a string' do
19
+ dsl.namespace(:monkey) { }
20
+ expect(Restspec::NamespaceStore.first.name).to eq('monkey')
21
+ end
22
+
23
+ it 'creates a namespace with the given base_path' do
24
+ dsl.namespace(:monkey, base_path: '/monkey') { }
25
+ expect(Restspec::NamespaceStore.first.full_base_path).to eq('/monkey')
26
+ end
27
+
28
+ it 'yields a Restspec::Endpoints::NamespaceDSL attached to the namespace to the block' do
29
+ namespace_dsl = OpenStruct.new(call: true)
30
+
31
+ allow(namespace_dsl).to receive(:call).and_return(true)
32
+ allow(Restspec::Endpoints::NamespaceDSL).to receive(:new) do |namespace|
33
+ namespace_dsl.namespace = namespace
34
+ namespace_dsl
35
+ end
36
+
37
+ dsl.namespace(:monkey) do
38
+ self.call
39
+ end
40
+
41
+ expect(namespace_dsl).to have_received(:call)
42
+ expect(namespace_dsl.namespace).to eq(Restspec::NamespaceStore.first)
43
+ end
44
+ end
45
+
46
+ describe '#resource' do
47
+ it 'creates a namespace with the base_path equals to /:name' do
48
+ dsl.resource(:monkeys) { }
49
+ expect(Restspec::NamespaceStore.first.full_base_path).to eq('/monkeys')
50
+ end
51
+
52
+ it 'creates a namespace with the schema attached to some schema with the same name' do
53
+ dsl.resource(:monkeys) { }
54
+ expect(Restspec::NamespaceStore.first.schema_name).to eq(:monkey)
55
+ end
56
+ end
57
+
58
+ describe Restspec::Endpoints::NamespaceDSL do
59
+ let(:namespace) { Restspec::Endpoints::Namespace.new(:monkeys) }
60
+ let(:ns_dsl) { Restspec::Endpoints::NamespaceDSL.new(namespace) }
61
+
62
+ describe '#endpoint' do
63
+ it 'creates an endpoint for the namespace' do
64
+ expect do
65
+ ns_dsl.endpoint(:show) { }
66
+ end.to change { Restspec::EndpointStore.size }.by(1)
67
+ end
68
+
69
+ it 'creates an endpoint with the full name of the endpoint' do
70
+ ns_dsl.endpoint(:show) { }
71
+ expect(Restspec::EndpointStore.get("monkeys/show")).to be_present
72
+ end
73
+ end
74
+
75
+ describe 'HTTP_METHODS calls' do
76
+ Restspec::Endpoints::HTTP_METHODS.each do |http_method|
77
+ describe "##{http_method}" do
78
+ it "creates an endpoint with the method set to #{http_method} and the correct path" do
79
+ ns_dsl.send(http_method, :show, '/hola')
80
+ endpoint = Restspec::EndpointStore.get("monkeys/show")
81
+ expect(endpoint.method).to eq(http_method)
82
+ expect(endpoint.path).to eq('/hola')
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ describe '#schema' do
89
+ it 'sets the schema_name of the namespace' do
90
+ expect do
91
+ ns_dsl.schema :schema_name
92
+ end.to change { namespace.schema_name }.to(:schema_name)
93
+ end
94
+ end
95
+
96
+ describe '#all' do
97
+ it 'calls the same block in all the endpoints inside' do
98
+ ns_dsl.all do
99
+ schema :a_schema_name
100
+ end
101
+
102
+ ns_dsl.endpoint(:a) { }
103
+ ns_dsl.endpoint(:b) { }
104
+
105
+ endpoint_a = Restspec::EndpointStore.get('monkeys/a')
106
+ endpoint_b = Restspec::EndpointStore.get('monkeys/b')
107
+
108
+ expect(endpoint_a.schema_name).to eq(:a_schema_name)
109
+ expect(endpoint_b.schema_name).to eq(:a_schema_name)
110
+ end
111
+ end
112
+
113
+ describe '#url_param' do
114
+ it 'sets the url_params in each endpoint' do
115
+ ns_dsl.url_param(:param) { 'value' }
116
+
117
+ ns_dsl.endpoint(:a) { }
118
+ ns_dsl.endpoint(:b) { }
119
+
120
+ Restspec::EndpointStore.each do |_, endpoint|
121
+ expect(endpoint.url_params[:param]).to eq('value')
122
+ end
123
+ end
124
+ end
125
+
126
+ describe 'resource sub-methods' do
127
+ let(:namespace) do
128
+ dsl.resource(:monkeys) { }
129
+ Restspec::NamespaceStore.get(:monkeys)
130
+ end
131
+
132
+ shared_examples :anonymous_namespace_method do |method_name|
133
+ it 'does not adds itself to the NamespaceStore' do
134
+ expect do
135
+ ns_dsl.send(method_name) { }
136
+ end.to_not change { Restspec::EndpointStore.size }
137
+ end
138
+
139
+ it 'creates a namespace inside the parent namespace' do
140
+ expect do
141
+ ns_dsl.send(method_name) { }
142
+ end.to change { namespace.children_namespaces.size }.by(1)
143
+ end
144
+
145
+ it 'creates an anonymous namespace' do
146
+ ns_dsl.send(method_name) { }
147
+ expect(namespace.children_namespaces.first).to be_anonymous
148
+ end
149
+ end
150
+
151
+ describe '#member' do
152
+ it 'adds a namespace that attaches the namespace parent base_path and the /:id path to the endpoints inside' do
153
+ ns_dsl.member do
154
+ endpoint(:a) { }
155
+ endpoint(:b) { path '/home' }
156
+ end
157
+
158
+ expect(Restspec::EndpointStore.get("monkeys/a").full_path).to eq('/monkeys/:id')
159
+ expect(Restspec::EndpointStore.get("monkeys/b").full_path).to eq('/monkeys/:id/home')
160
+ end
161
+
162
+ it_behaves_like :anonymous_namespace_method, :member
163
+ end
164
+
165
+ describe '#collection' do
166
+ it 'adds a namespace that attaches the previous base_path to the current path' do
167
+ ns_dsl.collection do
168
+ endpoint(:a) { }
169
+ endpoint(:b) { path '/home' }
170
+ end
171
+
172
+ expect(Restspec::EndpointStore.get("monkeys/a").full_path).to eq('/monkeys')
173
+ expect(Restspec::EndpointStore.get("monkeys/b").full_path).to eq('/monkeys/home')
174
+ end
175
+
176
+ it_behaves_like :anonymous_namespace_method, :collection
177
+ end
178
+ end
179
+ end
180
+
181
+ describe Restspec::Endpoints::EndpointDSL do
182
+ let(:endpoint) { Restspec::Endpoints::Endpoint.new }
183
+ let(:endpoint_dsl) { Restspec::Endpoints::EndpointDSL.new(endpoint) }
184
+
185
+ describe '#method' do
186
+ it 'sets the method of the endpoint' do
187
+ expect { endpoint_dsl.method :get }.to change { endpoint.method }.to(:get)
188
+ end
189
+ end
190
+
191
+ describe '#path' do
192
+ it 'sets the path of the endpoint' do
193
+ expect {
194
+ endpoint_dsl.path '/hola'
195
+ }.to change { endpoint.full_path }.from(nil).to('/hola')
196
+ end
197
+ end
198
+
199
+ describe '#schema' do
200
+ it 'sets the schema_name' do
201
+ expect {
202
+ endpoint_dsl.schema :monkey
203
+ }.to change { endpoint.schema_name }.from(nil).to(:monkey)
204
+ end
205
+
206
+ it 'sets the schema_name with schema_extensions' do
207
+ extensions = { a: 1, b: 2, c: 3 }
208
+
209
+ expect {
210
+ endpoint_dsl.schema :monkey, extensions
211
+ }.to change { endpoint.schema_extensions }.from(nil).to(extensions)
212
+ end
213
+ end
214
+
215
+ describe '#headers' do
216
+ it 'changes the headers of the endpoint' do
217
+ expect do
218
+ endpoint_dsl.headers['hola'] = 'mundo'
219
+ end.to change { endpoint.headers['hola'] }.from(nil).to('mundo')
220
+ end
221
+ end
222
+
223
+ describe '#url_param' do
224
+ context 'with a block returning a raw value' do
225
+ it 'adds the raw param to the endpoint' do
226
+ endpoint_dsl.url_param(:param) { 'param' }
227
+ expect(endpoint.url_params).to have_key(:param)
228
+ expect(endpoint.url_params[:param]).to eq('param')
229
+ end
230
+ end
231
+
232
+ context 'with a block returning a schema type' do
233
+ let(:type) { Restspec::Schema::Types::StringType.new }
234
+
235
+ before do
236
+ allow(type).to receive(:example_for).and_return('')
237
+ end
238
+
239
+ it 'executes example_for in the type' do
240
+ type = self.type
241
+
242
+ endpoint_dsl.url_param(:param) { type }
243
+ found_param = endpoint.url_params[:param]
244
+
245
+ expect(type).to have_received(:example_for)
246
+ expect(found_param).to eq('')
247
+ end
248
+
249
+ context 'when the endpoint has a schema' do
250
+ let(:schema) { double(attributes: { param: 1 }) }
251
+
252
+ before do
253
+ allow(endpoint).to receive(:schema).and_return(schema)
254
+ end
255
+
256
+ it 'calls the example_for with the attribute from the schema' do
257
+ type = self.type
258
+
259
+ endpoint_dsl.url_param(:param) { type }
260
+ found_param = endpoint.url_params[:param]
261
+
262
+ expect(type).to have_received(:example_for).with(1)
263
+ end
264
+ end
265
+ end
266
+ end
267
+ end
268
+ end
269
+