rspec-api 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{LICENSE.txt → MIT-LICENSE} +1 -3
- data/README.md +1 -28
- data/lib/rspec-api/accept_helper.rb +59 -0
- data/lib/rspec-api/api_helper.rb +67 -0
- data/lib/rspec-api/attributes_helper.rb +53 -0
- data/lib/rspec-api/description_helper.rb +55 -0
- data/lib/rspec-api/dsl.rb +8 -0
- data/lib/rspec-api/instances_helper.rb +37 -0
- data/lib/rspec-api/version.rb +3 -0
- metadata +20 -31
- data/.gitignore +0 -17
- data/Gemfile +0 -4
- data/Rakefile +0 -1
- data/lib/rspec/api.rb +0 -7
- data/lib/rspec/api/version.rb +0 -5
- data/rspec-api.gemspec +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80ddaf39a5b7ad64bec2e973e89771183f139ed2
|
4
|
+
data.tar.gz: c5b3280cd6f9b23bd127fd43db4487ded01c8a9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe877acbc40ca26a6dde50984ce03c62a485d7833fc2c175389a323a74debb9c189fd531a120cb83cf8541d8e6461afefeb36a43954a4a8d208ad9520e35f52a
|
7
|
+
data.tar.gz: d80f970b130815b361bac32f81f6d4623ae6345a514c6a0917a709596fc066bea127f6a1e2fbc112b6cf5597c33ab1e273972fadc5da1887ed8cfbe1391ed728
|
data/{LICENSE.txt → MIT-LICENSE}
RENAMED
data/README.md
CHANGED
@@ -1,29 +1,2 @@
|
|
1
|
-
#
|
1
|
+
# RSpec API
|
2
2
|
|
3
|
-
TODO: Write a gem description
|
4
|
-
|
5
|
-
## Installation
|
6
|
-
|
7
|
-
Add this line to your application's Gemfile:
|
8
|
-
|
9
|
-
gem 'rspec-api'
|
10
|
-
|
11
|
-
And then execute:
|
12
|
-
|
13
|
-
$ bundle
|
14
|
-
|
15
|
-
Or install it yourself as:
|
16
|
-
|
17
|
-
$ gem install rspec-api
|
18
|
-
|
19
|
-
## Usage
|
20
|
-
|
21
|
-
TODO: Write usage instructions here
|
22
|
-
|
23
|
-
## Contributing
|
24
|
-
|
25
|
-
1. Fork it
|
26
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
-
5. Create new Pull Request
|
@@ -0,0 +1,59 @@
|
|
1
|
+
def accepts(options = {}, &block)
|
2
|
+
parameters = block_given? ? options.merge(block: block) : options
|
3
|
+
(metadata[:query_parameters] ||= []).push parameters
|
4
|
+
end
|
5
|
+
|
6
|
+
RSpec::Matchers.define :be_sorted_by do |attribute|
|
7
|
+
match do |items|
|
8
|
+
values = items.map{|item| item[attribute.to_s]}
|
9
|
+
values.reverse! if example.metadata[:request_params][:sort][0] == '-'
|
10
|
+
values == values.sort
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def assert_pagination_links
|
15
|
+
expect(response_headers).to have_key 'Link'
|
16
|
+
links = response_headers['Link'].split(',')
|
17
|
+
rels = links.map{|link| link[/<.+?>; rel="(.*)"$/, 1]}
|
18
|
+
expect(rels).to match_array ['last', 'next']
|
19
|
+
end
|
20
|
+
|
21
|
+
def query_parameters_requests
|
22
|
+
metadata.fetch(:query_parameters, []).map do |params|
|
23
|
+
if params.has_key? :filter
|
24
|
+
filter_parameters_requests params
|
25
|
+
elsif params.has_key? :sort
|
26
|
+
sort_parameters_requests params
|
27
|
+
elsif params.has_key? :page
|
28
|
+
page_parameters_requests params
|
29
|
+
end
|
30
|
+
end.flatten
|
31
|
+
end
|
32
|
+
|
33
|
+
def filter_parameters_requests(params)
|
34
|
+
params.except(:given, :block).tap do |req|
|
35
|
+
value = params.fetch :given, apply(:as_json, to: existing(params[:on]))
|
36
|
+
req[:description] = " filtered by #{params[:filter]}"
|
37
|
+
req[:request_params] = {params[:filter] => value}
|
38
|
+
req[:block] = params[:block]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def sort_parameters_requests(params)
|
43
|
+
[true, false].map do |ascending|
|
44
|
+
params.except(:block).tap do |req|
|
45
|
+
req[:description] = " sorted by #{params[:sort]} #{ascending ? '↑' : '↓'}"
|
46
|
+
req[:request_params] = {sort: "#{ascending ? '' : '-'}#{params[:sort]}"}
|
47
|
+
req[:block] = params[:block]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def page_parameters_requests(params)
|
53
|
+
{}.tap do |req|
|
54
|
+
req[:description] = " paginated by #{params[:page]}"
|
55
|
+
(req[:request_params] = {})[params[:page]] = 1
|
56
|
+
req[:min_pages] = 2
|
57
|
+
req[:block] = -> _ { assert_pagination_links }
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
shared_context 'accept_json', accepts: :json do
|
3
|
+
header 'Accept', 'application/json'
|
4
|
+
end
|
5
|
+
|
6
|
+
shared_context 'return_json', returns: :json do
|
7
|
+
after { expect(json_response?) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def request(description, request_params = {})
|
11
|
+
default_request = {}
|
12
|
+
example_requests = [default_request]
|
13
|
+
example_requests.concat query_parameters_requests if metadata[:array]
|
14
|
+
|
15
|
+
example_requests.each do |request_metadata|
|
16
|
+
(request_metadata[:description] ||= '').prepend description
|
17
|
+
(request_metadata[:request_params] ||= {}).merge! request_params
|
18
|
+
metadata.merge! request_metadata
|
19
|
+
yield if block_given?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def request_params
|
24
|
+
example.metadata[:request_params]
|
25
|
+
end
|
26
|
+
|
27
|
+
def respond_with(expected_status, &block)
|
28
|
+
description = metadata[:description]
|
29
|
+
example description do
|
30
|
+
setup_instances
|
31
|
+
evaluate_request_params!
|
32
|
+
do_request request_params.dup
|
33
|
+
assert_response expected_status, &example.metadata.fetch(:block, block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def assert_response(expected_status, &block)
|
38
|
+
assert_status expected_status
|
39
|
+
if block_given? || success? && returns_content?
|
40
|
+
json = JSON response_body
|
41
|
+
assert_attributes json if success?
|
42
|
+
assert_instances json
|
43
|
+
instance_exec(json, &block) if block_given?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def evaluate_request_params!
|
48
|
+
request_params.each do |name, value|
|
49
|
+
request_params[name] = instance_exec(&value) if value.is_a? Proc
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def success?
|
54
|
+
status < 400
|
55
|
+
end
|
56
|
+
|
57
|
+
def returns_content?
|
58
|
+
[100, 101, 102, 204, 205, 304].exclude? status
|
59
|
+
end
|
60
|
+
|
61
|
+
def assert_status(expected_status)
|
62
|
+
expect(status).to be Rack::Utils.status_code(expected_status)
|
63
|
+
end
|
64
|
+
|
65
|
+
def json_response?
|
66
|
+
response_headers['Content-Type'] == 'application/json; charset=utf-8'
|
67
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rspec_api_documentation/dsl'
|
3
|
+
|
4
|
+
def has_attribute(name, type, options = {})
|
5
|
+
(metadata[:attributes] ||= {})[name] = options.merge(type: type)
|
6
|
+
end
|
7
|
+
|
8
|
+
def assert_attributes(json)
|
9
|
+
expect(json).to be_a (example.metadata[:array] ? Array : Hash)
|
10
|
+
example.metadata[:attributes].each do |name, options|
|
11
|
+
values = Array.wrap(json).map{|item| item[name.to_s]}
|
12
|
+
assert_attribute_types(values, options[:type], options[:can_be_nil])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def random_values_for_attributes
|
17
|
+
{}.tap do |values|
|
18
|
+
example.metadata[:attributes].each do |name, options|
|
19
|
+
can_be_nil = options[:can_be_nil] && (name != example.metadata[:on])
|
20
|
+
values[name] = random_attribute_value options.merge(can_be_nil: can_be_nil)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def random_attribute_value(options)
|
26
|
+
if options[:can_be_nil] && [true, false].sample
|
27
|
+
nil
|
28
|
+
else
|
29
|
+
case options[:type]
|
30
|
+
when :string then [*('a'..'z'), *('A'..'Z')].sample(Random.rand 32).join
|
31
|
+
when :integer then Random.rand(2**16)
|
32
|
+
when :url then "http://example.com/#{SecureRandom.urlsafe_base64}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def assert_attribute_types(values, expected_type, can_be_nil)
|
38
|
+
values.compact! if can_be_nil
|
39
|
+
expect(values).to all_match_type expected_type
|
40
|
+
end
|
41
|
+
|
42
|
+
def matches_type?(value, type)
|
43
|
+
case type
|
44
|
+
when :url then value =~ URI::regexp
|
45
|
+
else value.is_a? type.to_s.classify.constantize
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
RSpec::Matchers.define :all_match_type do |type|
|
50
|
+
match do |values|
|
51
|
+
values.all? {|value| matches_type? value, type}
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
def existing(key)
|
2
|
+
metadata[:description_attribute] = 'an existing'
|
3
|
+
-> { instances.any key }
|
4
|
+
end
|
5
|
+
|
6
|
+
def unknown(key)
|
7
|
+
metadata[:description_attribute] = 'an unknown'
|
8
|
+
-> { instances.none key }
|
9
|
+
end
|
10
|
+
|
11
|
+
def apply(method_name, options = {})
|
12
|
+
proc = options[:to]
|
13
|
+
-> { proc.call.send method_name }
|
14
|
+
end
|
15
|
+
|
16
|
+
def with(request_params = {})
|
17
|
+
request_params[:attribute] ||= metadata.delete :description_attribute
|
18
|
+
request description_for(request_params), request_params, &Proc.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def no_params
|
22
|
+
{}
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid(request_params)
|
26
|
+
request_params.merge attribute: 'an valid'
|
27
|
+
end
|
28
|
+
|
29
|
+
def invalid(request_params)
|
30
|
+
request_params.merge attribute: 'an invalid'
|
31
|
+
end
|
32
|
+
|
33
|
+
def description_for(request_params = {})
|
34
|
+
[description_verb, description_object(request_params)].join ' '
|
35
|
+
end
|
36
|
+
|
37
|
+
def description_verb
|
38
|
+
case metadata[:method]
|
39
|
+
when :get then 'Getting'
|
40
|
+
when :post then 'Creating'
|
41
|
+
when :put then 'Updating'
|
42
|
+
when :delete then 'Deleting'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def description_object(request_params = {})
|
47
|
+
attribute = request_params.delete :attribute
|
48
|
+
if metadata[:array]
|
49
|
+
"a list of #{metadata[:resource_name]}".tap do |objects|
|
50
|
+
objects << " by #{request_params.keys.join(', ')}" if request_params.any?
|
51
|
+
end
|
52
|
+
else
|
53
|
+
[attribute, metadata[:resource_name].singularize].join ' '
|
54
|
+
end.downcase
|
55
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
def setup_instances
|
2
|
+
instances.create random_values_for_attributes
|
3
|
+
instances.create random_values_for_attributes
|
4
|
+
stub_instances_total_pages example.metadata[:min_pages]
|
5
|
+
end
|
6
|
+
|
7
|
+
def instances
|
8
|
+
example.metadata[:resource_name].singularize.constantize
|
9
|
+
end
|
10
|
+
|
11
|
+
def assert_instances(json)
|
12
|
+
expect(json).not_to be_empty
|
13
|
+
end
|
14
|
+
|
15
|
+
def existing(key)
|
16
|
+
-> { instances.pluck(key).first }
|
17
|
+
end
|
18
|
+
|
19
|
+
def unknown(key)
|
20
|
+
keys = 0.downto(-Float::INFINITY).lazy
|
21
|
+
-> { keys.reject {|value| instances.exists? key => value}.first }
|
22
|
+
end
|
23
|
+
|
24
|
+
def apply(method_name, options = {})
|
25
|
+
proc = options[:to]
|
26
|
+
-> { proc.call.send method_name }
|
27
|
+
end
|
28
|
+
|
29
|
+
def stub_instances_total_pages(total_pages)
|
30
|
+
return unless instances.respond_to?(:page) and total_pages.present?
|
31
|
+
page_method = instances.method :page
|
32
|
+
instances.stub(:page) do |page|
|
33
|
+
page_method.call(page).tap do |proxy|
|
34
|
+
proxy.stub(:total_pages).and_return total_pages
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
metadata
CHANGED
@@ -1,59 +1,46 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- claudiob
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ~>
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.3'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ~>
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.3'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
14
|
+
name: rspec-api-documentation
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
30
16
|
requirements:
|
31
17
|
- - '>='
|
32
18
|
- !ruby/object:Gem::Version
|
33
19
|
version: '0'
|
34
|
-
type: :
|
20
|
+
type: :runtime
|
35
21
|
prerelease: false
|
36
22
|
version_requirements: !ruby/object:Gem::Requirement
|
37
23
|
requirements:
|
38
24
|
- - '>='
|
39
25
|
- !ruby/object:Gem::Version
|
40
26
|
version: '0'
|
41
|
-
description:
|
27
|
+
description: Helpers to write specs for web APIs
|
42
28
|
email:
|
43
29
|
- claudiob@gmail.com
|
44
30
|
executables: []
|
45
31
|
extensions: []
|
46
32
|
extra_rdoc_files: []
|
47
33
|
files:
|
48
|
-
- .
|
49
|
-
-
|
50
|
-
-
|
34
|
+
- lib/rspec-api/accept_helper.rb
|
35
|
+
- lib/rspec-api/api_helper.rb
|
36
|
+
- lib/rspec-api/attributes_helper.rb
|
37
|
+
- lib/rspec-api/description_helper.rb
|
38
|
+
- lib/rspec-api/dsl.rb
|
39
|
+
- lib/rspec-api/instances_helper.rb
|
40
|
+
- lib/rspec-api/version.rb
|
41
|
+
- MIT-LICENSE
|
51
42
|
- README.md
|
52
|
-
-
|
53
|
-
- lib/rspec/api.rb
|
54
|
-
- lib/rspec/api/version.rb
|
55
|
-
- rspec-api.gemspec
|
56
|
-
homepage: ''
|
43
|
+
homepage: https://github.com/claudiob/rspec-api
|
57
44
|
licenses:
|
58
45
|
- MIT
|
59
46
|
metadata: {}
|
@@ -65,16 +52,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
52
|
requirements:
|
66
53
|
- - '>='
|
67
54
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
55
|
+
version: 1.9.0
|
69
56
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
57
|
requirements:
|
71
58
|
- - '>='
|
72
59
|
- !ruby/object:Gem::Version
|
73
|
-
version:
|
60
|
+
version: 1.3.6
|
74
61
|
requirements: []
|
75
62
|
rubyforge_project:
|
76
|
-
rubygems_version: 2.0
|
63
|
+
rubygems_version: 2.1.0
|
77
64
|
signing_key:
|
78
65
|
specification_version: 4
|
79
|
-
summary:
|
66
|
+
summary: Extends rspec_api_documentation with methods to write more compact and meaningful,
|
67
|
+
auto-documented specs for web APIs.
|
80
68
|
test_files: []
|
69
|
+
has_rdoc:
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/Rakefile
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
data/lib/rspec/api.rb
DELETED
data/lib/rspec/api/version.rb
DELETED
data/rspec-api.gemspec
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'rspec/api/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "rspec-api"
|
8
|
-
spec.version = Rspec::Api::VERSION
|
9
|
-
spec.authors = ["claudiob"]
|
10
|
-
spec.email = ["claudiob@gmail.com"]
|
11
|
-
spec.description = %q{Write a gem description}
|
12
|
-
spec.summary = %q{Write a gem summary}
|
13
|
-
spec.homepage = ""
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.files = `git ls-files`.split($/)
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = ["lib"]
|
20
|
-
|
21
|
-
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
-
spec.add_development_dependency "rake"
|
23
|
-
end
|