rspec-api 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|