restspec 0.0.1

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