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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2630d035050223be7f59896a2d36084c4f1b710a
4
+ data.tar.gz: 180d28e725e189ffee1f2da1186d89bb6ed04048
5
+ SHA512:
6
+ metadata.gz: c105cb126412bb60802fc54b83b9ad9e42cc50e14d41ddc9bb73f79acf396357906448d2f8657b01a1ca4cfe76597595bc2ae21debe281b2a09939442964611b
7
+ data.tar.gz: f6740670155d18921523cfef7a45dff961aa22745af928f23d214296bb492ba918a4fbd7310e39d795fd305cff24a0afc242e7750dc84169e330044ec7801eb9
@@ -0,0 +1,21 @@
1
+ # No .editorconfig files above the root directory
2
+ root = true
3
+
4
+ [*]
5
+ indent_style = space
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+
11
+ [*.{rb}]
12
+ indent_size = 2
13
+
14
+ [Gemfile*]
15
+ indent_size = 2
16
+
17
+ [Rakefile]
18
+ indent_size = 2
19
+
20
+ [Guardfile]
21
+ indent_size = 2
@@ -0,0 +1,23 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.DS_Store
16
+ .tags
17
+ .tags_sorted_by_file
18
+
19
+ examples/store-api/tmp/pids
20
+ examples/store-api/tmp/
21
+ examples/store-api/log/*.log
22
+ examples/store-api/.rbenv-vars
23
+ examples/store-api/db/*.sqlite3
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --require spec_helper
3
+ --format documentation
4
+ --format Nc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in restspec.gemspec
4
+ gemspec
@@ -0,0 +1,6 @@
1
+ guard :rspec, cmd: 'bundle exec rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
6
+
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 juliogarciag
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,188 @@
1
+ # Restspec
2
+
3
+ Restspec is a REST api framework built in top of RSpec to help you write robust and mantainable tests to ensure that your api behaves exactly as you want.
4
+
5
+ ## Installation
6
+
7
+ Install it globally like this:
8
+
9
+ $ gem install restspec
10
+
11
+ ## Usage
12
+
13
+ For a basic tutorial of how to use Restspec, please check [this file](https://github.com/platanus/restspec/blob/master/docs/tutorial.md).
14
+
15
+ ### The Restspec Approach
16
+
17
+ You can skip this section but i think it will help you understand how things happens here. The Restspec design is founded in the separation of how your api components are modeled and what the actual tests are. In Restspec, you have three files intended to model your api:
18
+
19
+ - endpoints.rb
20
+ - schemas.rb
21
+ - requirements.rb
22
+
23
+ The only one that is completely necesary is the `endpoints.rb` file. This file is when you define what your endpoints are and give them names. For example, the following endpoint: `GET /users/:id/orders` can be mapped to an endpoint named `users/orders`. This name can be used to reference and execute the endpoint in the tests instead of repeating it many times.
24
+
25
+ The next one, `schemas.rb`, represents the attributes your entities are made of, and the final one, `requirements.rb` only helps to ensure that some information is already present on the system when the tests begin.
26
+
27
+ When we talk about endpoints as objects to reuse, we can think of the dependencies between the endpoints as dependencies between models. We can just make the `product/show` endpoint to depend on the `products/index` and the `products/create` endpoints to make sure that the test always run with a product.
28
+
29
+ ### Setup
30
+
31
+ To create a new test for a given api, just run the following command:
32
+
33
+ ```bash
34
+ $ restspec my-api-tests --api-prefix=http://my-api-domain/api/v1
35
+ ```
36
+
37
+ This will create a folder called `my-api-tests` with the following contents:
38
+
39
+ ```
40
+ .
41
+ ├── Gemfile
42
+ ├── Gemfile.lock
43
+ └── spec
44
+ ├── api
45
+ │   └── restspec
46
+ │   ├── endpoints.rb
47
+ │   ├── requirements.rb
48
+ │   ├── schemas.rb
49
+ │   └── restspec_config.rb
50
+ ├── spec_helper.rb
51
+ └── support
52
+ ├── custom_macros.rb
53
+ └── custom_matchers.rb
54
+ ```
55
+
56
+ Your tests go anywhere (you can put them in the api/ folder), the configuration file (`restspec_config.rb`) has his own documentation inside and the endpoints and schemas file are were you define the inner parts of the expected API. `requirements.rb` is a set of requirement to assert needs before some tests, like to test that an api key is valid or that the system already has some important data that can't be created through the api.
57
+
58
+ ### Endpoints
59
+
60
+ In the endpoints file you can define your endpoints using an special dsl, like this:
61
+
62
+ ```ruby
63
+ resources :products do
64
+ collection do
65
+ get :index
66
+ end
67
+
68
+ member do
69
+ get :show
70
+ end
71
+ end
72
+ ```
73
+
74
+ Check the endpoint DSL documentation [here](https://github.com/platanus/restspec/blob/master/docs/endpoints.md) for more details of the available methods and options. The only important thing about them is that they are the endpoints we have to test.
75
+
76
+ ### Schemas
77
+
78
+ Schemas are how your data is shaped and they enforces the shape of the your data and how to generates random examples for that. You can define schemas using a special dsl like this:
79
+
80
+ ```ruby
81
+ schema :product do
82
+ attribute :name, string
83
+ attribute :code, string
84
+ attribute :price, decimal | decimal_string
85
+ attribute :category_id, schema_id(:category), :for => [:examples]
86
+ attribute :category, embedded_schema(:category), :for => [:checks]
87
+ end
88
+
89
+ schema :category do
90
+ attribute :name, string
91
+ end
92
+ ```
93
+
94
+ As you can see, a schema is compound of attributes that are attached to one type. The types are useful for many things. The types documentation is located [here](https://github.com/platanus/restspec/blob/master/docs/types.md).
95
+
96
+ The schemas DSL documentation is located [here](https://github.com/platanus/restspec/blob/master/docs/schemas.md). Schemas are a very important part of Restspec but they are not as necesary as the endpoints.
97
+
98
+ ### Tests
99
+
100
+ To actually test something, let's create any test of type `api` (because in the `restspec/restspec_config` file we added helpers and macros only for this type of tests). To test an endpoint of your api you have to use the `endpoint` macro
101
+
102
+ ```ruby
103
+ endpoint 'products/index' do
104
+ end
105
+ ```
106
+
107
+ To actually test an execution of the endpoint, you have to use the `test` method. Restspec tests are not unit ones because the cost of call a possible slow api can be high. Because of this, all the `it`s blocks that are under a `test` block will only execute the endpoint once. Because of this, we can test many assertions against only one api execution:
108
+
109
+ ```ruby
110
+ endpoint 'products/index' do
111
+ test do
112
+ it { should have_status(:ok) }
113
+ it 'returns an array' do
114
+ expect(body).to be_kind_of(Array)
115
+ end
116
+ end
117
+ end
118
+ ```
119
+
120
+ We can call other endpoints from inside a test. For example:
121
+
122
+ ```ruby
123
+ endpoint 'products/create' do
124
+ # ...
125
+ test 'Without a price' do
126
+ # This is the `payload` macro, to fill the request's payload
127
+ payload name: 'random name'
128
+
129
+ it 'has the price set to 0' do
130
+ product = read_endpoint(url_params: { id: body.id })
131
+ expect(product.price).to eq(0)
132
+ end
133
+ end
134
+ end
135
+ ```
136
+
137
+ Aditionally, we can test an endpoint that is intended to represent an action over a resource. For example, an update can be tested like this:
138
+
139
+ ```ruby
140
+ endpoint 'products/update', resource: 'products/show' do
141
+ # initial_resource is the initial representation of the resource
142
+ payload do
143
+ { name: "#{initial_resource.name}-001" }
144
+ end
145
+
146
+ test do
147
+ it 'updates the name' do
148
+ # final resource is the representation of the resource after
149
+ # the endpoint has been executed
150
+ expect(final_resource.name).to_not eq(initial_resource.name)
151
+ expect(final_resource.name).to eq(request.payload.name)
152
+ end
153
+ end
154
+ end
155
+ ```
156
+
157
+ For more information about what can you do in your tests, you can see what are the [available matchers](https://github.com/platanus/restspec/blob/master/docs/matchers.md), the [available helpers](https://github.com/platanus/restspec/blob/master/docs/helpers.md) and the [available macros](https://github.com/platanus/restspec/blob/master/docs/macros.md).
158
+
159
+ ### Requirements
160
+
161
+ They allow to check for something important before starting to test.
162
+
163
+ ```ruby
164
+ requirement :check_warehouse_availability do
165
+ execution do
166
+ warehouses = read_endpoint('warehouses/index')
167
+ if !warehouses || warehouses.empty?
168
+ add_error "There is no warehouses in the system"
169
+ end
170
+ end
171
+ end
172
+ ```
173
+
174
+ To use them, you have to do the following in your test:
175
+
176
+ ```ruby
177
+ endpoint 'products/create' do
178
+ ensure! :check_warehouse_availability
179
+ end
180
+ ```
181
+
182
+ ## A note about the Roadmap
183
+
184
+ Because the scope of this library is not small, we couldn't make a first release as small as we are acostumed. Anyway, we love to be able to deliver in small iterations, so there a [ROADMAP](https://github.com/platanus/restspec/blob/master/ROADMAP.md) file that we use to keep track of the objectives that we have. Althought many of the objectives of the gem are already done, there are more objectives that will expect to the following releases.
185
+
186
+ ## Contribute
187
+
188
+ Please be sure to have the [EditorConfig](http://editorconfig.org/) plugin in your text editor to follow the guidelines proposed in the [.editorconfig](https://github.com/platanus/restspec/blob/master/.editorconfig) file. To contribute, please send us a PR and make sure that the current tests keeps working after that. You can help to complete the unit tests too. Anyway, when we have all tests together, we should have Travis working, but, right now, it's ok for us to just test the PR before going on.
@@ -0,0 +1,11 @@
1
+ # For 0.1.x
2
+ - 100% Test coverage.
3
+ - Include Travis.
4
+ - Test the restspec binary.
5
+ - Find a way to support a way of authentication based on cookies with an initial login.
6
+ - Find a way to avoid example value clashes when using resource tests.
7
+ - Schemas mixins or/and schemas inheritance.
8
+
9
+ # For 0.2 (They require more thoughts)
10
+ - Research pagination strategies and integrating them with `schema_id`.
11
+ - Research some way to generate markdown from a mix of the schemas and endpoints. (Like Apiary and others)
@@ -0,0 +1,20 @@
1
+ require 'rspec/core/rake_task'
2
+ require 'bundler/gem_tasks'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
8
+ namespace :restspec do
9
+ task :run_example_app do
10
+ Dir.chdir("examples/store-api") do
11
+ exec("BUNDLE_GEMFILE=Gemfile bundle exec rails s -p 3000")
12
+ end
13
+ end
14
+
15
+ task :run_example_tests do
16
+ Dir.chdir("examples/store-api-tests") do
17
+ exec("BUNDLE_GEMFILE=Gemfile bundle exec rspec spec/")
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'thor/group'
4
+
5
+ class RestspecRunner < Thor::Group
6
+ include Thor::Actions
7
+
8
+ argument :project
9
+
10
+ class_option :api_prefix, :desc => "api prefix to use", :required => true
11
+
12
+ def self.source_root
13
+ File.dirname(__FILE__)
14
+ end
15
+
16
+ def create_project_dir
17
+ empty_directory project
18
+ end
19
+
20
+ def copy_gemfile
21
+ copy_file 'templates/Gemfile', "#{project}/Gemfile"
22
+ end
23
+
24
+ def create_spec_folders
25
+ empty_directory "#{project}/spec"
26
+ empty_directory "#{project}/spec/api"
27
+ empty_directory "#{project}/spec/support"
28
+ end
29
+
30
+ def create_spec_helper
31
+ template 'templates/spec_helper.rb', "#{project}/spec/spec_helper.rb"
32
+ end
33
+
34
+ def create_rspec_config
35
+ template 'templates/restspec_config.rb', "#{project}/spec/api/restspec/restspec_config.rb"
36
+ end
37
+
38
+ def create_api_dsl_files
39
+ create_file "#{project}/spec/api/restspec/api_endpoints.rb"
40
+ create_file "#{project}/spec/api/restspec/api_schemas.rb"
41
+ create_file "#{project}/spec/api/restspec/api_requirements.rb"
42
+ end
43
+
44
+ def create_support_files
45
+ create_file "#{project}/spec/support/custom_matchers.rb"
46
+ copy_file "templates/custom_macros.rb", "#{project}/spec/support/custom_macros.rb"
47
+ end
48
+
49
+ def install_gems
50
+ inside(project) { run 'bundle install' }
51
+ end
52
+ end
53
+
54
+ RestspecRunner.start(ARGV)
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'restspec'
@@ -0,0 +1,3 @@
1
+ module CustomMacros
2
+
3
+ end
@@ -0,0 +1,10 @@
1
+ Restspec.configure do |config|
2
+ config.base_url = '<%= options[:api_prefix] %>'
3
+ config.schema_definition = "#{File.dirname __FILE__}/schemas.rb"
4
+ config.endpoints_definition = "#{File.dirname __FILE__}/endpoints.rb"
5
+ config.requirements_definition = "#{File.dirname __FILE__}/requirements.rb"
6
+ #
7
+ # => to add custom headers, use config.request.headers like this:
8
+ #
9
+ # config.request.headers['AUTHORIZATION'] = "Token token=\"#{config.custom.api_key}\""
10
+ end
@@ -0,0 +1,19 @@
1
+ require 'restspec'
2
+
3
+ Dir["#{File.dirname __FILE__}/support/**/*.rb"].each {|f| require f}
4
+
5
+ RSpec.configure do |config|
6
+ config.expect_with :rspec do |expectations|
7
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
8
+ end
9
+
10
+ config.mock_with :rspec do |mocks|
11
+ mocks.verify_partial_doubles = true
12
+ end
13
+
14
+ config.include Restspec::RSpec::ApiHelpers, :type => :api
15
+ config.extend Restspec::RSpec::ApiMacros, :type => :api
16
+ config.extend CustomMacros, :type => :api
17
+ end
18
+
19
+ require_relative './api/restspec/restspec_config'
@@ -0,0 +1,200 @@
1
+ # Endpoints Full DSL
2
+
3
+ ## Top Level DSL
4
+
5
+ ### namespace
6
+
7
+ The `namespace` method creates a namespace for a set of endpoints, giving them a prefix in his names.
8
+
9
+ ```ruby
10
+ namespace :animals do
11
+ endpoint :show
12
+ endpoint :update
13
+ end
14
+ ```
15
+
16
+ ### resource
17
+
18
+ The `resource` method creates a special namespace that has a `base_path` attribute set to his name. It can optionally receives a `base_path` option with a different path.
19
+
20
+ ```ruby
21
+ resource :animals do
22
+ endpoint :get
23
+ end
24
+
25
+ resource :light_sabers, base_path: '/light-sabers' do
26
+ endpoint :get
27
+ end
28
+ ```
29
+
30
+ It's important to note that the endpoints inside the `resource` block doesn't necessarily have the resource's namespace attached to them. For this to happen, we have to have the endpoints inside an `member` or `collection` method.
31
+
32
+ ## Namespace DSL
33
+
34
+ ### endpoint
35
+
36
+ The `endpoint` method only specifies a new endpoint. The block it yields (using the endpoint dsl) specifies how the endpoint is.
37
+
38
+ ### member
39
+
40
+ Inside the `member` block inside a `resource`, you can specify a set of endpoints that inherits the `base_path` of the resource and the `/:id` string for the final url.
41
+
42
+ ```ruby
43
+ resource :books do # /books
44
+ member do # /books/:id
45
+ endpoint :show # /books/:id. The name is: books/show
46
+ end
47
+ end
48
+ ```
49
+
50
+
51
+ ### collection
52
+
53
+ Inside the `collection` method you can specify a set of endpoint that only inherits the `base_path`. It's useful to define resource collection actions, like typicals `create` or `index`.
54
+
55
+ ```ruby
56
+ resource :books do # /books
57
+ collection do # /books
58
+ endpoint :create # /books
59
+ end
60
+ end
61
+ ```
62
+
63
+ ### schema
64
+
65
+ You can attach a namespace to an schema. For example, you can attach the `book` schema to the `books` namespace because `book` related endpoints should be related to entities that conforms to the `book` schema. This is useful for some types, matchers and macros that can take adventage of this relationship.
66
+
67
+ ```ruby
68
+ resource :books do
69
+ schema :book
70
+ end
71
+ ```
72
+
73
+ ### all
74
+
75
+ The `all` method yields a block that will be executed in each endpoint defined.
76
+
77
+ ```ruby
78
+ resource :books do
79
+ all do
80
+ method :get
81
+ end
82
+
83
+ endpoint :create # this will have the get method
84
+ endpoint :index # this too
85
+ end
86
+ ```
87
+
88
+ ### url_param
89
+
90
+ This is just a proxy using `all`. This method calls the method `url_param` of each one of the endpoints with the given params. Please look at the `url_param` method of the Endpoints DSL.
91
+
92
+ ### get, post, put, patch, delete, head
93
+
94
+ This methods are shortcuts for the following pattern:
95
+
96
+ ```ruby
97
+ resource :books do
98
+ endpoint :published do
99
+ method :get
100
+ path '/published'
101
+ end
102
+ end
103
+
104
+ # shortcut:
105
+ resource :books do
106
+ get :published, '/published'
107
+ end
108
+ ```
109
+
110
+ ## Endpoints DSL
111
+
112
+ ### method
113
+
114
+ Defines what http method the endpoint holds.
115
+
116
+ ```ruby
117
+ resource :books do
118
+ collection do
119
+ endpoint :index do
120
+ method :get
121
+ end
122
+ end
123
+ end
124
+ ```
125
+
126
+ ### path
127
+
128
+ Defines what path the endpoint holds. By default, is empty.
129
+
130
+ ```ruby
131
+ resource :books do
132
+ collection do
133
+ endpoint :published do
134
+ method :get
135
+ path '/published'
136
+ end
137
+ end
138
+ end
139
+ ```
140
+
141
+ ### schema
142
+
143
+ Attaches an schema to the endpoint. This provides some data for helpers, matchers and macros. If the endpoint's schema is nil, the endpoint's schema will be his namespace's schema.
144
+
145
+ ```ruby
146
+ resource :books do
147
+ collection do
148
+ endpoint :published do
149
+ method :get
150
+ path '/published'
151
+ schema :published_book
152
+ end
153
+ end
154
+ end
155
+ ```
156
+
157
+ ### headers
158
+
159
+ It is a hash that represents the endpoint headers. It can be modified to add new headers.
160
+
161
+ ```ruby
162
+ resource :books do
163
+ collection do
164
+ endpoint :published do
165
+ method :get
166
+ path '/published'
167
+ schema :published_book
168
+ # Let's imagine this endpoint is going to a very weird system
169
+ headers['Content-Type'] = 'application/json; charset=windows-1252'
170
+ end
171
+ end
172
+ end
173
+ ```
174
+
175
+ ### url_param
176
+
177
+ It fills a url parameter (the part of the path with a colon behind: `:id`, `:book_id`, etc) with the given value or block
178
+
179
+ ```ruby
180
+ resource :books do
181
+ member do
182
+ endpoint :show do
183
+ url_param(:id) { 998 }
184
+ method :get
185
+ end
186
+ end
187
+ end
188
+ ```
189
+
190
+ Or, using the shortcut for `get` requests:
191
+
192
+ ```ruby
193
+ resource :books do
194
+ member do
195
+ get :show do
196
+ url_param(:id) { 998 }
197
+ end
198
+ end
199
+ end
200
+ ```