restful-matchers 0.2.1 → 0.3.0
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/CHANGELOG.md +16 -0
- data/Gemfile.lock +1 -5
- data/README.md +31 -8
- data/lib/restful/matchers.rb +3 -0
- data/lib/restful/matchers/errors.rb +2 -0
- data/lib/restful/matchers/errors/invalid_link.rb +7 -0
- data/lib/restful/matchers/have_link.rb +4 -12
- data/lib/restful/matchers/have_links.rb +68 -0
- data/lib/restful/matchers/parsers.rb +2 -0
- data/lib/restful/matchers/parsers/json_link_parser.rb +17 -0
- data/lib/restful/matchers/version.rb +5 -0
- data/restful-matchers.gemspec +11 -8
- data/spec/fixtures/json/resource_with_links.json +9 -0
- data/spec/restful/matchers/have_link_spec.rb +7 -19
- data/spec/restful/matchers/have_links_spec.rb +38 -0
- data/spec/restful/parsers/json_link_parser_spec.rb +24 -0
- metadata +13 -4
- data/spec/fixtures/json/resource.json +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ebf655f0413ddd8082f291573ce0072759b5578
|
4
|
+
data.tar.gz: 60d70c76fdc3491752fec9639bfc87129b759b04
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94c24744350d3810781943ea6e4c6db4029c8fbc82a8fab38ce65d65b31daca232d8fdf0cbf6b039a0b95365b0f9d952a5836ca290bd17063cc15bc3c915fbb2
|
7
|
+
data.tar.gz: 73146b6bae167a0443c4cb072220bab85b9b07c39c8a59906ffa9648c70f8d607fd89b8e247a405758d62bdd4e653cc33d9ced3a9702cb2e841bc486892bb7f3
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# HEAD
|
2
|
+
nothing yet.
|
3
|
+
|
4
|
+
# v0.3.0
|
5
|
+
* New matcher `have_links` to match many links at once.
|
6
|
+
|
7
|
+
# v0.2.1
|
8
|
+
* Show matched content on failure;
|
9
|
+
|
10
|
+
# v0.2.0
|
11
|
+
* Process both raw and parsed (hash) JSON representations;
|
12
|
+
* Attribute `href` is now optional;
|
13
|
+
* `have_restful_json_link` is an alias for `have_link` matcher (preffered).
|
14
|
+
|
15
|
+
# v0.1
|
16
|
+
* Initial version with `have_restful_json_link` matcher.
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
restful-matchers (0.
|
4
|
+
restful-matchers (0.3.0)
|
5
5
|
rspec (~> 2.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -26,9 +26,6 @@ GEM
|
|
26
26
|
diff-lcs (>= 1.1.3, < 2.0)
|
27
27
|
rspec-mocks (2.14.3)
|
28
28
|
slop (3.4.6)
|
29
|
-
step-up (0.9.1)
|
30
|
-
thor (>= 0.14.6)
|
31
|
-
thor (0.18.1)
|
32
29
|
|
33
30
|
PLATFORMS
|
34
31
|
ruby
|
@@ -39,4 +36,3 @@ DEPENDENCIES
|
|
39
36
|
pry-nav (~> 0.2)
|
40
37
|
rake (~> 10.1)
|
41
38
|
restful-matchers!
|
42
|
-
step-up (~> 0.9)
|
data/README.md
CHANGED
@@ -5,32 +5,47 @@ RSpec matchers to test RESTful HATEOAS-compliant resource links. Currently it su
|
|
5
5
|
|
6
6
|
## Usage
|
7
7
|
|
8
|
-
|
8
|
+
Let's say we have a `MyRestfulController#index` controller action that returns the following JSON representation, with links represented as an array of `{rel: ... , href: ...}` objects:
|
9
9
|
|
10
10
|
```json
|
11
11
|
{
|
12
12
|
"attribute1": "value1",
|
13
13
|
"attribute2": "value2",
|
14
14
|
"links": [
|
15
|
-
{ "rel": "
|
15
|
+
{ "rel": "foo", "href": "http://example.com/foo" }
|
16
|
+
{ "rel": "bar", "href": "http://example.com/bar" }
|
17
|
+
{ "rel": "baz", "href": "http://example.com/baz" }
|
18
|
+
{ "rel": "qux", "href": "http://example.com/qux" }
|
16
19
|
]
|
17
20
|
}
|
18
21
|
```
|
19
22
|
|
20
|
-
You can match links
|
23
|
+
You can match those links using `have_link` or `have_links` matchers as follow:
|
21
24
|
|
22
25
|
```ruby
|
23
26
|
describe MyRestfulController do
|
24
|
-
render_views
|
27
|
+
render_views # don't forget this!
|
25
28
|
|
26
29
|
it "should have links" do
|
27
30
|
get :index
|
28
31
|
|
29
|
-
|
30
|
-
response.body.should have_link "
|
32
|
+
# you can match against both raw ...
|
33
|
+
response.body.should have_link "foo", "http://example.com/foo"
|
34
|
+
response.body.should have_link "bar", "http://example.com/bar"
|
31
35
|
|
32
|
-
|
33
|
-
parsed_json
|
36
|
+
# ... or parsed JSON (as a Hash)
|
37
|
+
parsed_json = JSON.parse(response.body)
|
38
|
+
|
39
|
+
# href attribute is optional
|
40
|
+
parsed_json.should have_link "baz"
|
41
|
+
|
42
|
+
# match many links at once using have_links matcher
|
43
|
+
response.body.should have_links([
|
44
|
+
{ rel: "foo", href: "http://example.com/foo" },
|
45
|
+
{ rel: "bar", href: "http://example.com/bar" },
|
46
|
+
{ rel: "baz", href: "http://example.com/baz" },
|
47
|
+
{ rel: "qux", href: "http://example.com/qux" },
|
48
|
+
])
|
34
49
|
end
|
35
50
|
end
|
36
51
|
```
|
@@ -42,3 +57,11 @@ Add it to the `test` group in your Gemfile and be happy!
|
|
42
57
|
```ruby
|
43
58
|
gem 'restful-matchers', '~> 0.2', :group => :test
|
44
59
|
```
|
60
|
+
|
61
|
+
## Changelog
|
62
|
+
|
63
|
+
See [CHANGELOG](https://github.com/marcoshack/restful-matchers/blob/master/CHANGELOG.md).
|
64
|
+
|
65
|
+
## License
|
66
|
+
|
67
|
+
restful-matchers is Copyright © 2013 Marcos Hack. It is free software, and may be redistributed under the terms specified in the LICENSE file.
|
data/lib/restful/matchers.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'json'
|
2
|
+
require 'restful/matchers/parsers'
|
2
3
|
|
3
4
|
module RESTful
|
4
5
|
module Matchers
|
5
6
|
# Ensures that JSON response body has the given link.
|
6
7
|
#
|
7
8
|
# Example:
|
8
|
-
#
|
9
|
+
#
|
10
|
+
# response.body.should have_json_link("self", "http://example.com")
|
9
11
|
#
|
10
12
|
def have_link(rel, href = nil)
|
11
13
|
HaveLink.new(rel, href)
|
@@ -20,7 +22,7 @@ module RESTful
|
|
20
22
|
|
21
23
|
def matches?(content)
|
22
24
|
@content = content
|
23
|
-
if links =
|
25
|
+
if links = RESTful::Matchers::Parsers::JSONLinkParser.parse(content)
|
24
26
|
return @href ? links[@rel] == @href : links.has_key?(@rel)
|
25
27
|
else
|
26
28
|
return false
|
@@ -39,16 +41,6 @@ module RESTful
|
|
39
41
|
def error_message(message)
|
40
42
|
"#{message} '{\"rel\": \"#{@rel}\", \"href\": \"#{@href || "<any>" }\"}' in '#{@content}'"
|
41
43
|
end
|
42
|
-
|
43
|
-
def parse_links_from(content)
|
44
|
-
json = content.is_a?(Hash) ? content : JSON.parse(content)
|
45
|
-
links = nil
|
46
|
-
if json["links"]
|
47
|
-
links = {}
|
48
|
-
json["links"].each { |link| links[link["rel"]] = link["href"] }
|
49
|
-
end
|
50
|
-
return links
|
51
|
-
end
|
52
44
|
end
|
53
45
|
end
|
54
46
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'restful/matchers/parsers'
|
3
|
+
|
4
|
+
module RESTful
|
5
|
+
module Matchers
|
6
|
+
# Ensures that JSON response body has the given links, represented as an
|
7
|
+
# array of hashes with `rel` and `href` keys.
|
8
|
+
#
|
9
|
+
# Example:
|
10
|
+
#
|
11
|
+
# response.body.should have_links([
|
12
|
+
# { rel: "self", href: "http://example.com" },
|
13
|
+
# { rel: "foo" , href: "http://example.com/foo" },
|
14
|
+
# { rel: "bar" , href: "http://example.com/bar" }
|
15
|
+
# ])
|
16
|
+
#
|
17
|
+
def have_links(links)
|
18
|
+
HaveLinks.new(links)
|
19
|
+
end
|
20
|
+
|
21
|
+
class HaveLinks
|
22
|
+
def initialize(links)
|
23
|
+
@match_links = {}
|
24
|
+
|
25
|
+
if links.is_a?(Array)
|
26
|
+
links.each do |link|
|
27
|
+
rel = link[:rel] || link["rel"]
|
28
|
+
href = link[:href] || link["href"]
|
29
|
+
if rel
|
30
|
+
@match_links[rel.to_s] = href
|
31
|
+
else
|
32
|
+
raise ::Errors::InvalidLink("Link has no `rel`: #{link}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
else
|
36
|
+
raise ArgumentError.new("matcher expects an array of hashes containing `rel` and `href` keys as argument")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def matches?(content)
|
41
|
+
@content = content
|
42
|
+
@content_links = RESTful::Matchers::Parsers::JSONLinkParser.parse(content)
|
43
|
+
if @content_links
|
44
|
+
@content_links.each do |rel, href|
|
45
|
+
match = href ? @match_links[rel] == href : @match_links.has_key?(rel)
|
46
|
+
return false unless match
|
47
|
+
end
|
48
|
+
return true
|
49
|
+
else
|
50
|
+
return false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def failure_message_for_should
|
55
|
+
"Expected links weren't found. #{content_and_match_links_message}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def failure_message_for_should_not
|
59
|
+
"Not expected links where found. #{content_and_match_links_message}"
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
def content_and_match_links_message
|
64
|
+
"Expect '#{@match_links}', but got '#{@content_links}'."
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RESTful
|
2
|
+
module Matchers
|
3
|
+
module Parsers
|
4
|
+
module JSONLinkParser
|
5
|
+
def self.parse(content)
|
6
|
+
json = content.is_a?(Hash) ? content : JSON.parse(content)
|
7
|
+
links = nil
|
8
|
+
if json["links"]
|
9
|
+
links = {}
|
10
|
+
json["links"].each { |link| links[link["rel"]] = link["href"] }
|
11
|
+
end
|
12
|
+
return links
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/restful-matchers.gemspec
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
|
2
|
+
require 'restful/matchers/version'
|
2
3
|
|
3
4
|
Gem::Specification.new do |gem|
|
4
|
-
gem.name
|
5
|
-
gem.version
|
6
|
-
|
5
|
+
gem.name = "restful-matchers"
|
6
|
+
gem.version = RESTful::Matchers::VERSION.dup
|
7
|
+
gem.date = Time.now.strftime("%Y-%m-%d")
|
7
8
|
gem.authors = [ "Marcos Hack" ]
|
8
9
|
gem.email = [ "marcoshack@gmail.com" ]
|
9
10
|
gem.summary = "RSpec matchers to test RESTful HATEOAS-compliant resource links."
|
@@ -11,10 +12,12 @@ Gem::Specification.new do |gem|
|
|
11
12
|
gem.homepage = "https://github.com/marcoshack/restful-matchers"
|
12
13
|
gem.license = "MIT"
|
13
14
|
|
15
|
+
gem.files = `git ls-files`.split("\n")
|
16
|
+
gem.test_files = `git ls-files -- {spec}/*`.split("\n")
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
|
19
|
+
gem.required_ruby_version = '>= 1.9.2'
|
20
|
+
|
14
21
|
gem.add_dependency "rspec", "~> 2.0"
|
15
22
|
gem.add_development_dependency "bundler", "~> 1.0"
|
16
|
-
|
17
|
-
gem.files = `git ls-files`.split($\)
|
18
|
-
gem.test_files = gem.files.grep(/^(test)/)
|
19
|
-
gem.require_paths = ["lib"]
|
20
23
|
end
|
@@ -2,30 +2,18 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe RESTful::Matchers::HaveLink do
|
4
4
|
|
5
|
-
|
6
|
-
it "should find a json link" do
|
7
|
-
@content.should have_restful_json_link("self", "http://example.com")
|
8
|
-
@content.should have_link("self", "http://example.com")
|
9
|
-
end
|
5
|
+
before(:each) { @content = open("spec/fixtures/json/resource_with_links.json").read }
|
10
6
|
|
11
|
-
|
12
|
-
|
13
|
-
@content.should_not have_link("foo", "http://bar.com")
|
14
|
-
end
|
15
|
-
|
16
|
-
it "should find a link matching only the rel attribute" do
|
17
|
-
@content.should have_link("self")
|
18
|
-
end
|
7
|
+
it "should match a valid link" do
|
8
|
+
@content.should have_link("self", "http://example.com")
|
19
9
|
end
|
20
10
|
|
21
|
-
|
22
|
-
|
23
|
-
it_behaves_like "Matcher"
|
11
|
+
it "should not match a non-existing link" do
|
12
|
+
@content.should_not have_link("foo", "http://bar.com")
|
24
13
|
end
|
25
14
|
|
26
|
-
|
27
|
-
|
28
|
-
it_behaves_like "Matcher"
|
15
|
+
it "should match only by rel attribute" do
|
16
|
+
@content.should have_link("self")
|
29
17
|
end
|
30
18
|
|
31
19
|
it "should show matched content on fail" do
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RESTful::Matchers::HaveLinks do
|
4
|
+
|
5
|
+
context "when processing a valid JSON with links" do
|
6
|
+
let(:content) { open("spec/fixtures/json/resource_with_links.json").read }
|
7
|
+
|
8
|
+
it "should match an array of links using symbols as keys" do
|
9
|
+
content.should have_links([
|
10
|
+
{ rel: "self", href: "http://example.com" },
|
11
|
+
{ rel: "foo" , href: "http://example.com/foo" },
|
12
|
+
{ rel: "bar" , href: "http://example.com/bar" }
|
13
|
+
])
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should match an array of links using string as keys" do
|
17
|
+
content.should have_links([
|
18
|
+
{ "rel" => "self", "href" => "http://example.com" },
|
19
|
+
{ "rel" => "foo" , "href" => "http://example.com/foo" },
|
20
|
+
{ "rel" => "bar" , "href" => "http://example.com/bar" }
|
21
|
+
])
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not match an empty array" do
|
25
|
+
content.should_not have_links []
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should fail to match an empty array" do
|
29
|
+
expect { content.should have_links [] }.to raise_error(/.*Expect '{}'.*/)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should fail to match an invalid argument" do
|
33
|
+
[ 1, "", {}, :a_symbol, nil ].each do |value|
|
34
|
+
expect { content.should have_links value }.to raise_error(ArgumentError)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'restful/matchers/parsers/json_link_parser'
|
3
|
+
|
4
|
+
describe RESTful::Matchers::Parsers::JSONLinkParser do
|
5
|
+
shared_examples_for "parser" do
|
6
|
+
it "should parser links" do
|
7
|
+
links = RESTful::Matchers::Parsers::JSONLinkParser.parse(content)
|
8
|
+
links.keys.should include "self", "foo", "bar"
|
9
|
+
links["self"].should == "http://example.com"
|
10
|
+
links["foo" ].should == "http://example.com/foo"
|
11
|
+
links["bar" ].should == "http://example.com/bar"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when parsing raw JSON" do
|
16
|
+
let(:content) { open("spec/fixtures/json/resource_with_links.json").read }
|
17
|
+
it_behaves_like "parser"
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when parsing parsed JSON" do
|
21
|
+
let(:content) { JSON.parse(open("spec/fixtures/json/resource_with_links.json").read) }
|
22
|
+
it_behaves_like "parser"
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restful-matchers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcos Hack
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-08-
|
11
|
+
date: 2013-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -49,6 +49,7 @@ extra_rdoc_files: []
|
|
49
49
|
files:
|
50
50
|
- .gitignore
|
51
51
|
- .travis.yml
|
52
|
+
- CHANGELOG.md
|
52
53
|
- Gemfile
|
53
54
|
- Gemfile.lock
|
54
55
|
- LICENSE
|
@@ -56,11 +57,19 @@ files:
|
|
56
57
|
- Rakefile
|
57
58
|
- lib/restful-matchers.rb
|
58
59
|
- lib/restful/matchers.rb
|
60
|
+
- lib/restful/matchers/errors.rb
|
61
|
+
- lib/restful/matchers/errors/invalid_link.rb
|
59
62
|
- lib/restful/matchers/have_link.rb
|
63
|
+
- lib/restful/matchers/have_links.rb
|
60
64
|
- lib/restful/matchers/integrations/rspec.rb
|
65
|
+
- lib/restful/matchers/parsers.rb
|
66
|
+
- lib/restful/matchers/parsers/json_link_parser.rb
|
67
|
+
- lib/restful/matchers/version.rb
|
61
68
|
- restful-matchers.gemspec
|
62
|
-
- spec/fixtures/json/
|
69
|
+
- spec/fixtures/json/resource_with_links.json
|
63
70
|
- spec/restful/matchers/have_link_spec.rb
|
71
|
+
- spec/restful/matchers/have_links_spec.rb
|
72
|
+
- spec/restful/parsers/json_link_parser_spec.rb
|
64
73
|
- spec/spec_helper.rb
|
65
74
|
homepage: https://github.com/marcoshack/restful-matchers
|
66
75
|
licenses:
|
@@ -74,7 +83,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
74
83
|
requirements:
|
75
84
|
- - '>='
|
76
85
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
86
|
+
version: 1.9.2
|
78
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
88
|
requirements:
|
80
89
|
- - '>='
|