restspec 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +21 -0
- data/.gitignore +23 -0
- data/.rspec +4 -0
- data/Gemfile +4 -0
- data/Guardfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +188 -0
- data/ROADMAP.md +11 -0
- data/Rakefile +20 -0
- data/bin/restspec +54 -0
- data/bin/templates/Gemfile +3 -0
- data/bin/templates/custom_macros.rb +3 -0
- data/bin/templates/restspec_config.rb +10 -0
- data/bin/templates/spec_helper.rb +19 -0
- data/docs/endpoints.md +200 -0
- data/docs/helpers.md +40 -0
- data/docs/macros.md +140 -0
- data/docs/matchers.md +38 -0
- data/docs/schemas.md +28 -0
- data/docs/tutorial.md +477 -0
- data/docs/types.md +134 -0
- data/examples/store-api-tests/.rspec +3 -0
- data/examples/store-api-tests/Gemfile +4 -0
- data/examples/store-api-tests/Gemfile.lock +70 -0
- data/examples/store-api-tests/spec/api/category_spec.rb +23 -0
- data/examples/store-api-tests/spec/api/product_spec.rb +55 -0
- data/examples/store-api-tests/spec/api/restspec/endpoints.rb +39 -0
- data/examples/store-api-tests/spec/api/restspec/requirements.rb +0 -0
- data/examples/store-api-tests/spec/api/restspec/restspec_config.rb +6 -0
- data/examples/store-api-tests/spec/api/restspec/schemas.rb +11 -0
- data/examples/store-api-tests/spec/spec_helper.rb +19 -0
- data/examples/store-api-tests/spec/support/custom_macros.rb +3 -0
- data/examples/store-api-tests/spec/support/custom_matchers.rb +0 -0
- data/examples/store-api/.editorconfig +24 -0
- data/examples/store-api/.rbenv-vars.example +3 -0
- data/examples/store-api/.rspec +4 -0
- data/examples/store-api/.ruby-version +1 -0
- data/examples/store-api/Gemfile +58 -0
- data/examples/store-api/Gemfile.lock +216 -0
- data/examples/store-api/Guardfile +39 -0
- data/examples/store-api/README.md +1 -0
- data/examples/store-api/Rakefile +6 -0
- data/examples/store-api/app/assets/images/.keep +0 -0
- data/examples/store-api/app/assets/javascripts/application.js +16 -0
- data/examples/store-api/app/assets/javascripts/categories.js.coffee +3 -0
- data/examples/store-api/app/assets/javascripts/products.js.coffee +3 -0
- data/examples/store-api/app/assets/stylesheets/application.css +15 -0
- data/examples/store-api/app/assets/stylesheets/categories.css.scss +3 -0
- data/examples/store-api/app/assets/stylesheets/products.css.scss +3 -0
- data/examples/store-api/app/assets/stylesheets/scaffolds.css.scss +69 -0
- data/examples/store-api/app/controllers/application_controller.rb +5 -0
- data/examples/store-api/app/controllers/categories_controller.rb +74 -0
- data/examples/store-api/app/controllers/concerns/.keep +0 -0
- data/examples/store-api/app/controllers/products_controller.rb +74 -0
- data/examples/store-api/app/helpers/application_helper.rb +2 -0
- data/examples/store-api/app/helpers/categories_helper.rb +2 -0
- data/examples/store-api/app/helpers/products_helper.rb +2 -0
- data/examples/store-api/app/mailers/.keep +0 -0
- data/examples/store-api/app/models/.keep +0 -0
- data/examples/store-api/app/models/category.rb +2 -0
- data/examples/store-api/app/models/concerns/.keep +0 -0
- data/examples/store-api/app/models/product.rb +3 -0
- data/examples/store-api/app/views/categories/_form.html.erb +21 -0
- data/examples/store-api/app/views/categories/edit.html.erb +6 -0
- data/examples/store-api/app/views/categories/index.html.erb +25 -0
- data/examples/store-api/app/views/categories/index.json.jbuilder +4 -0
- data/examples/store-api/app/views/categories/new.html.erb +5 -0
- data/examples/store-api/app/views/categories/show.html.erb +9 -0
- data/examples/store-api/app/views/categories/show.json.jbuilder +1 -0
- data/examples/store-api/app/views/layouts/application.html.erb +14 -0
- data/examples/store-api/app/views/products/_form.html.erb +29 -0
- data/examples/store-api/app/views/products/edit.html.erb +6 -0
- data/examples/store-api/app/views/products/index.html.erb +29 -0
- data/examples/store-api/app/views/products/index.json.jbuilder +4 -0
- data/examples/store-api/app/views/products/new.html.erb +5 -0
- data/examples/store-api/app/views/products/show.html.erb +19 -0
- data/examples/store-api/app/views/products/show.json.jbuilder +6 -0
- data/examples/store-api/bin/bundle +3 -0
- data/examples/store-api/bin/guard +16 -0
- data/examples/store-api/bin/rails +8 -0
- data/examples/store-api/bin/rake +8 -0
- data/examples/store-api/bin/spring +18 -0
- data/examples/store-api/config.ru +4 -0
- data/examples/store-api/config/application.rb +30 -0
- data/examples/store-api/config/boot.rb +4 -0
- data/examples/store-api/config/database.yml +25 -0
- data/examples/store-api/config/environment.rb +5 -0
- data/examples/store-api/config/environments/development.rb +37 -0
- data/examples/store-api/config/environments/production.rb +78 -0
- data/examples/store-api/config/environments/test.rb +39 -0
- data/examples/store-api/config/initializers/assets.rb +8 -0
- data/examples/store-api/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/store-api/config/initializers/cookies_serializer.rb +3 -0
- data/examples/store-api/config/initializers/filter_parameter_logging.rb +4 -0
- data/examples/store-api/config/initializers/inflections.rb +16 -0
- data/examples/store-api/config/initializers/mime_types.rb +4 -0
- data/examples/store-api/config/initializers/session_store.rb +3 -0
- data/examples/store-api/config/initializers/wrap_parameters.rb +14 -0
- data/examples/store-api/config/locales/en.yml +23 -0
- data/examples/store-api/config/routes.rb +59 -0
- data/examples/store-api/config/secrets.yml +22 -0
- data/examples/store-api/db/migrate/20141205154816_create_products.rb +11 -0
- data/examples/store-api/db/migrate/20141205171104_create_categories.rb +9 -0
- data/examples/store-api/db/migrate/20141205171140_add_category_id_to_products.rb +5 -0
- data/examples/store-api/db/schema.rb +31 -0
- data/examples/store-api/db/seeds.rb +7 -0
- data/examples/store-api/lib/assets/.keep +0 -0
- data/examples/store-api/lib/tasks/.keep +0 -0
- data/examples/store-api/log/.keep +0 -0
- data/examples/store-api/public/404.html +67 -0
- data/examples/store-api/public/422.html +67 -0
- data/examples/store-api/public/500.html +66 -0
- data/examples/store-api/public/favicon.ico +0 -0
- data/examples/store-api/public/robots.txt +5 -0
- data/examples/store-api/spec/controllers/categories_controller_spec.rb +159 -0
- data/examples/store-api/spec/controllers/products_controller_spec.rb +159 -0
- data/examples/store-api/spec/factories/categories.rb +6 -0
- data/examples/store-api/spec/factories/products.rb +8 -0
- data/examples/store-api/spec/helpers/categories_helper_spec.rb +15 -0
- data/examples/store-api/spec/helpers/products_helper_spec.rb +15 -0
- data/examples/store-api/spec/models/category_spec.rb +5 -0
- data/examples/store-api/spec/models/product_spec.rb +5 -0
- data/examples/store-api/spec/rails_helper.rb +50 -0
- data/examples/store-api/spec/requests/categories_spec.rb +10 -0
- data/examples/store-api/spec/requests/products_spec.rb +10 -0
- data/examples/store-api/spec/routing/categories_routing_spec.rb +35 -0
- data/examples/store-api/spec/routing/products_routing_spec.rb +35 -0
- data/examples/store-api/spec/spec_helper.rb +85 -0
- data/examples/store-api/spec/views/categories/edit.html.erb_spec.rb +18 -0
- data/examples/store-api/spec/views/categories/index.html.erb_spec.rb +19 -0
- data/examples/store-api/spec/views/categories/new.html.erb_spec.rb +18 -0
- data/examples/store-api/spec/views/categories/show.html.erb_spec.rb +14 -0
- data/examples/store-api/spec/views/products/edit.html.erb_spec.rb +24 -0
- data/examples/store-api/spec/views/products/index.html.erb_spec.rb +25 -0
- data/examples/store-api/spec/views/products/new.html.erb_spec.rb +24 -0
- data/examples/store-api/spec/views/products/show.html.erb_spec.rb +18 -0
- data/examples/store-api/vendor/assets/javascripts/.keep +0 -0
- data/examples/store-api/vendor/assets/stylesheets/.keep +0 -0
- data/lib/restspec.rb +38 -0
- data/lib/restspec/configuration.rb +43 -0
- data/lib/restspec/endpoints/dsl.rb +142 -0
- data/lib/restspec/endpoints/endpoint.rb +135 -0
- data/lib/restspec/endpoints/namespace.rb +89 -0
- data/lib/restspec/endpoints/network.rb +39 -0
- data/lib/restspec/endpoints/request.rb +11 -0
- data/lib/restspec/endpoints/response.rb +53 -0
- data/lib/restspec/requirements/dsl.rb +10 -0
- data/lib/restspec/requirements/requirement.rb +59 -0
- data/lib/restspec/rspec/api_helpers.rb +64 -0
- data/lib/restspec/rspec/api_macros.rb +126 -0
- data/lib/restspec/rspec/extras.rb +2 -0
- data/lib/restspec/rspec/matchers/api_matchers.rb +6 -0
- data/lib/restspec/rspec/matchers/be_like_schema.rb +18 -0
- data/lib/restspec/rspec/matchers/be_like_schema_array.rb +18 -0
- data/lib/restspec/rspec/matchers/have_header.rb +47 -0
- data/lib/restspec/rspec/matchers/have_status.rb +17 -0
- data/lib/restspec/rspec/matchers/include_where.rb +14 -0
- data/lib/restspec/rspec/shared_examples.rb +12 -0
- data/lib/restspec/schema/attribute.rb +31 -0
- data/lib/restspec/schema/attribute_example.rb +21 -0
- data/lib/restspec/schema/checker.rb +73 -0
- data/lib/restspec/schema/dsl.rb +36 -0
- data/lib/restspec/schema/schema.rb +21 -0
- data/lib/restspec/schema/schema_example.rb +28 -0
- data/lib/restspec/schema/types.rb +35 -0
- data/lib/restspec/schema/types/array_type.rb +34 -0
- data/lib/restspec/schema/types/basic_type.rb +35 -0
- data/lib/restspec/schema/types/boolean_type.rb +11 -0
- data/lib/restspec/schema/types/decimal_string_type.rb +32 -0
- data/lib/restspec/schema/types/decimal_type.rb +14 -0
- data/lib/restspec/schema/types/embedded_schema_type.rb +28 -0
- data/lib/restspec/schema/types/hash_type.rb +25 -0
- data/lib/restspec/schema/types/integer_type.rb +11 -0
- data/lib/restspec/schema/types/null_type.rb +11 -0
- data/lib/restspec/schema/types/one_of_type.rb +21 -0
- data/lib/restspec/schema/types/schema_id_type.rb +88 -0
- data/lib/restspec/schema/types/string_type.rb +11 -0
- data/lib/restspec/shortcuts.rb +8 -0
- data/lib/restspec/stores/endpoint_store.rb +25 -0
- data/lib/restspec/stores/namespace_store.rb +20 -0
- data/lib/restspec/stores/schema_store.rb +19 -0
- data/lib/restspec/values/status_code.rb +13 -0
- data/lib/restspec/values/super_hash.rb +12 -0
- data/lib/restspec/version.rb +3 -0
- data/restspec.gemspec +37 -0
- data/spec/restspec/endpoints/dsl_spec.rb +269 -0
- data/spec/restspec/endpoints/endpoint_spec.rb +146 -0
- data/spec/restspec/endpoints/namespace_spec.rb +143 -0
- data/spec/restspec/endpoints/response_spec.rb +49 -0
- data/spec/restspec/schema/attribute_example_spec.rb +35 -0
- data/spec/restspec/schema/dsl_spec.rb +78 -0
- data/spec/restspec/schema/schema_example_spec.rb +40 -0
- data/spec/restspec/schema/schema_spec.rb +11 -0
- data/spec/restspec/schema/types/array_type_spec.rb +56 -0
- data/spec/restspec/schema/types/basic_type_spec.rb +62 -0
- data/spec/restspec/schema/types/boolean_type_spec.rb +26 -0
- data/spec/restspec/schema/types/null_type_spec.rb +25 -0
- data/spec/restspec/schema/types/string_type_spec.rb +26 -0
- data/spec/restspec/values/status_code_spec.rb +13 -0
- data/spec/spec_helper.rb +23 -0
- metadata +484 -0
checksums.yaml
ADDED
@@ -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
|
data/.editorconfig
ADDED
@@ -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
|
data/.gitignore
ADDED
@@ -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
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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.
|
data/ROADMAP.md
ADDED
@@ -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)
|
data/Rakefile
ADDED
@@ -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
|
data/bin/restspec
ADDED
@@ -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,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'
|
data/docs/endpoints.md
ADDED
@@ -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
|
+
```
|