rspec-hal 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/lib/rspec/hal/matchers.rb +32 -84
- data/lib/rspec/hal/matchers/hal_matcher_helpers.rb +65 -0
- data/lib/rspec/hal/matchers/have_property_matcher.rb +69 -0
- data/lib/rspec/hal/matchers/relation_matcher.rb +69 -0
- data/lib/rspec/hal/matchers/templated_relation_matcher.rb +5 -30
- data/lib/rspec/hal/version.rb +1 -1
- data/spec/rspec/hal/matchers/have_property_matcher_spec.rb +126 -0
- data/spec/rspec/hal/matchers/relation_matcher_spec.rb +173 -0
- data/spec/rspec/hal/matchers/templated_relation_matcher_spec.rb +4 -4
- data/spec/rspec/hal/matchers_spec.rb +1 -45
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5db7232aae0766a25700b98a53d8c343c0eb8f91
|
4
|
+
data.tar.gz: 560a463c6967e2c0f060aec76c688d007cf08756
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dfe7e6f2a41a4dce154256da82f2789d40db8509e5be62f7658a9db46ec97a3bdfdaa25e88669300158008dddb4aa1b320b0bae52aac65975646c02e11841231
|
7
|
+
data.tar.gz: f48fead8ad5405d19646fe6c01b5d07518978f475f6683089d8ce0a65e09b46ba41d4246cb4244a9aa2bcdd1a2e2d0aa6953990a64ae18a7aae61c94b78868f0
|
data/README.md
CHANGED
@@ -35,6 +35,8 @@ Once you have the matchers included you can use it like this
|
|
35
35
|
.including(a_hash_including('type' => 'sport'))
|
36
36
|
|
37
37
|
expect(a_user_doc).to have_relation('tag')
|
38
|
+
expect(a_user_doc).to have_templated_relation("search")
|
39
|
+
expect(a_user_doc).to have_templated_relation("search", matching("{?q}"))
|
38
40
|
```
|
39
41
|
|
40
42
|
## Installation
|
@@ -60,4 +62,4 @@ Or install it yourself as:
|
|
60
62
|
5. Push to the branch (`git push origin my-new-feature`)
|
61
63
|
6. Create new Pull Request
|
62
64
|
|
63
|
-
[semver]: http://semver.org
|
65
|
+
[semver]: http://semver.org
|
data/lib/rspec/hal/matchers.rb
CHANGED
@@ -4,7 +4,10 @@ require 'hal-client'
|
|
4
4
|
module RSpec
|
5
5
|
module Hal
|
6
6
|
module Matchers
|
7
|
+
autoload :HalMatcherHelpers, "rspec/hal/matchers/hal_matcher_helpers"
|
8
|
+
require "rspec/hal/matchers/relation_matcher"
|
7
9
|
require "rspec/hal/matchers/templated_relation_matcher"
|
10
|
+
require "rspec/hal/matchers/have_property_matcher"
|
8
11
|
|
9
12
|
# Examples
|
10
13
|
#
|
@@ -15,6 +18,35 @@ module RSpec
|
|
15
18
|
TemplatedRelationMatcher.new(*args)
|
16
19
|
end
|
17
20
|
|
21
|
+
# Signature
|
22
|
+
#
|
23
|
+
# expect(doc).to have_relation(link_rel)
|
24
|
+
# expect(doc).to have_relation(link_rel, href_matcher)
|
25
|
+
# expect(doc).to have_relation(link_rel, template_variables)
|
26
|
+
# expect(doc).to have_relation(link_rel, template_variables, href_matcher)
|
27
|
+
#
|
28
|
+
# Examples
|
29
|
+
#
|
30
|
+
# expect(authors_doc).to have_relation("search",
|
31
|
+
# {q: "Alice"},
|
32
|
+
# match(%r|users/42|))
|
33
|
+
def have_relation(*args)
|
34
|
+
RelationMatcher.new(*args)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Signature
|
38
|
+
#
|
39
|
+
# expect(a_doc).to have_property "name"
|
40
|
+
# expect(a_doc).to have_property "name, matching(/alice/i)
|
41
|
+
#
|
42
|
+
# expect(a_doc).to have_property("name").matching(/alice/i)
|
43
|
+
# expect(a_doc).to have_property("hobbies").including(matching("golf"))
|
44
|
+
# expect(a_doc).to have_property("name").that_is("Bob")
|
45
|
+
# expect(a_doc).to have_property("age").that_is kind_of Numeric
|
46
|
+
def have_property(*args)
|
47
|
+
HavePropertyMatcher.new(*args)
|
48
|
+
end
|
49
|
+
|
18
50
|
module Document
|
19
51
|
extend RSpec::Matchers::DSL
|
20
52
|
|
@@ -74,91 +106,7 @@ module RSpec
|
|
74
106
|
"Expected `$._embedded.item` to exist in:\n" + a_doc
|
75
107
|
end
|
76
108
|
end
|
77
|
-
|
78
|
-
# Check that the document has the specified property.
|
79
|
-
#
|
80
|
-
# Signature
|
81
|
-
#
|
82
|
-
# expect(a_user_doc).to have_property "name"
|
83
|
-
# expect(a_user_doc).to have_property("name").that_is("Bob")
|
84
|
-
# expect(a_user_doc).to have_property("age").that_is kind_of Numeric
|
85
|
-
# expect(a_user_doc).to have_property("name").matching(/bob/i)
|
86
|
-
# expect(a_user_doc).to have_property("hobbies").including(matching("golf"))
|
87
|
-
matcher :have_property do |prop_name|
|
88
|
-
match do |a_doc|
|
89
|
-
a_doc = JSON.load(a_doc) rescue a_doc
|
90
|
-
|
91
|
-
|
92
|
-
next false unless a_doc.key? prop_name
|
93
|
-
|
94
|
-
__value_matcher === a_doc.fetch(prop_name)
|
95
|
-
end
|
96
|
-
|
97
|
-
chain :that_is do |expected_val|
|
98
|
-
@value_matcher = expected_val
|
99
|
-
end
|
100
|
-
|
101
|
-
chain :matching do |val_pat|
|
102
|
-
@value_matcher = if Regexp === val_pat
|
103
|
-
RSpec::Matchers::BuiltIn::Match.new val_pat
|
104
|
-
else
|
105
|
-
val_pat
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
chain :including do |val_pat|
|
110
|
-
@value_matcher = RSpec::Matchers::BuiltIn::Include.new val_pat
|
111
|
-
end
|
112
|
-
|
113
|
-
failure_message do
|
114
|
-
msg = super()
|
115
|
-
if @value_matcher
|
116
|
-
msg + " " + @value_matcher.description.gsub(/^match /, "matching ")
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
define_method(:__value_matcher) do
|
121
|
-
@value_matcher || ->(*_){ true }
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
# Check that the document has the specified relation (in
|
126
|
-
# either the _links or _embedded sections.
|
127
|
-
#
|
128
|
-
# Signature
|
129
|
-
#
|
130
|
-
# expect(a_user_doc).to have_relation "tag"
|
131
|
-
matcher :have_relation do |link_rel|
|
132
|
-
match do |a_doc|
|
133
|
-
a_doc = JSON.load(a_doc) rescue a_doc
|
134
|
-
repr = HalClient::Representation.new(parsed_json: a_doc)
|
135
|
-
|
136
|
-
begin
|
137
|
-
repr.related_hrefs(link_rel) .any?{|an_href|
|
138
|
-
next true if !defined? @href_matcher
|
139
|
-
@href_matcher === an_href
|
140
|
-
}
|
141
|
-
rescue KeyError
|
142
|
-
false
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
chain :with_href do |expected_href|
|
147
|
-
(fail ArgumentError, "#{expected_href.inspect} must be a matcher") unless expected_href.respond_to? :matches?
|
148
|
-
|
149
|
-
@href_matcher = expected_href
|
150
|
-
end
|
151
|
-
|
152
|
-
failure_message do
|
153
|
-
msg = super()
|
154
|
-
if @href_matcher
|
155
|
-
msg + " with href " + @href_matcher.description.gsub(/^match /, "matching ")
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
end
|
160
109
|
end
|
161
|
-
|
162
110
|
include Document
|
163
111
|
end
|
164
112
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Hal
|
3
|
+
module Matchers
|
4
|
+
module HalMatcherHelpers
|
5
|
+
NullMatcher = Class.new do
|
6
|
+
def matches(*args)
|
7
|
+
true
|
8
|
+
end
|
9
|
+
def ===(*args)
|
10
|
+
true
|
11
|
+
end
|
12
|
+
def description
|
13
|
+
""
|
14
|
+
end
|
15
|
+
end.new
|
16
|
+
|
17
|
+
# Returns string composed of the specified clauses with proper
|
18
|
+
# spacing between them. Empty and nil clauses are ignored.
|
19
|
+
def sentencize(*clauses)
|
20
|
+
clauses
|
21
|
+
.flatten
|
22
|
+
.compact
|
23
|
+
.reject(&:empty?)
|
24
|
+
.map(&:strip)
|
25
|
+
.join(" ")
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns HalClient::Representation of the provided jsonish
|
29
|
+
# thing.
|
30
|
+
#
|
31
|
+
# jsonish - A HAL document (as a string or pre-parsed hash) or
|
32
|
+
# an object that can be converted into one via its `#to_hal`
|
33
|
+
# or `#to_json` methods.
|
34
|
+
def parse(jsonish)
|
35
|
+
json = if jsonish.kind_of? String
|
36
|
+
jsonish
|
37
|
+
|
38
|
+
elsif jsonish.respond_to? :to_hal
|
39
|
+
jsonish.to_hal
|
40
|
+
|
41
|
+
else jsonish.respond_to? :to_json
|
42
|
+
jsonish.to_json
|
43
|
+
end
|
44
|
+
|
45
|
+
HalClient::Representation.new(parsed_json: MultiJson.load(json))
|
46
|
+
end
|
47
|
+
|
48
|
+
def matcherize(expected)
|
49
|
+
if matcher? expected
|
50
|
+
expected
|
51
|
+
elsif expected.kind_of? Regexp
|
52
|
+
RSpec::Matchers::BuiltIn::Match.new(expected)
|
53
|
+
else
|
54
|
+
RSpec::Matchers::BuiltIn::Eq.new(expected)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def matcher?(obj)
|
59
|
+
obj.respond_to?(:matches?) and (obj.respond_to?(:failure_message) or
|
60
|
+
obj.respond_to?(:failure_message_for_should))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Hal
|
3
|
+
module Matchers
|
4
|
+
|
5
|
+
# Example
|
6
|
+
#
|
7
|
+
# expect(doc).to have_property("name")
|
8
|
+
# expect(doc).to have_property("search", matching("Alice"))
|
9
|
+
#
|
10
|
+
class HavePropertyMatcher
|
11
|
+
include HalMatcherHelpers
|
12
|
+
|
13
|
+
def initialize(property_name, expected=NullMatcher)
|
14
|
+
@prop_name = property_name
|
15
|
+
@expected = expected
|
16
|
+
end
|
17
|
+
|
18
|
+
def matches?(jsonish)
|
19
|
+
repr = parse(jsonish)
|
20
|
+
|
21
|
+
repr.property?(prop_name) &&
|
22
|
+
expected === repr.property(prop_name){ nil }
|
23
|
+
end
|
24
|
+
|
25
|
+
def failure_message
|
26
|
+
but_clause = if outcome == :no_templates
|
27
|
+
"found only non-templated links"
|
28
|
+
else
|
29
|
+
"found none"
|
30
|
+
end
|
31
|
+
expected_clause = if expected != NullMatcher && expected.respond_to?(:description)
|
32
|
+
expected.description
|
33
|
+
elsif expected != NullMatcher
|
34
|
+
"matching #{expected}"
|
35
|
+
else
|
36
|
+
"to exist"
|
37
|
+
end
|
38
|
+
|
39
|
+
"Expected templated `#{link_rel}` link #{expected_clause} but #{but_clause}"
|
40
|
+
end
|
41
|
+
alias_method :failure_message_for_should, :failure_message
|
42
|
+
|
43
|
+
def failure_message_when_negated
|
44
|
+
"Expected `#{link_rel}` link to be absent or not templated"
|
45
|
+
end
|
46
|
+
alias_method :failure_message_for_should_not, :failure_message_when_negated
|
47
|
+
|
48
|
+
def description
|
49
|
+
"have property `#{prop_name}` #{@expected.description}"
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def matching(expected)
|
54
|
+
self.class.new(prop_name, matcherize(expected))
|
55
|
+
end
|
56
|
+
alias_method :that_is, :matching
|
57
|
+
|
58
|
+
def including(expected)
|
59
|
+
self.class.new(prop_name, RSpec::Matchers::BuiltIn::Include.new(expected))
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
attr_reader :prop_name, :outcome, :expected
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Hal
|
3
|
+
module Matchers
|
4
|
+
|
5
|
+
# Example
|
6
|
+
#
|
7
|
+
# expect(doc).to have_relation("search")
|
8
|
+
# expect(doc).to have_relation("search", matching("{?q}"))
|
9
|
+
#
|
10
|
+
class RelationMatcher
|
11
|
+
include HalMatcherHelpers
|
12
|
+
|
13
|
+
# Signature
|
14
|
+
#
|
15
|
+
# expect(doc).to have_relation link_rel
|
16
|
+
# expect(doc).to have_relation link_rel, href_matcher
|
17
|
+
# expect(doc).to have_relation link_rel, template_variables
|
18
|
+
# expect(doc).to have_relation link_rel, template_variables, href_matcher
|
19
|
+
def initialize(link_rel, *args)
|
20
|
+
@link_rel = link_rel
|
21
|
+
|
22
|
+
@tmpl_vars, @expected = *if args.empty?
|
23
|
+
[{},NullMatcher]
|
24
|
+
elsif args.size > 1
|
25
|
+
args
|
26
|
+
elsif hashish? args.first
|
27
|
+
[args.first, NullMatcher]
|
28
|
+
else
|
29
|
+
[{}, args.first]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def matches?(jsonish)
|
34
|
+
repr = parse(jsonish)
|
35
|
+
|
36
|
+
repr.related_hrefs(link_rel, tmpl_vars){[]}
|
37
|
+
.select{|it| expected === it }
|
38
|
+
.any?
|
39
|
+
end
|
40
|
+
|
41
|
+
def failure_message
|
42
|
+
sentencize "Expected `#{link_rel}` link or embedded", expected.description, "but found none"
|
43
|
+
end
|
44
|
+
alias_method :failure_message_for_should, :failure_message
|
45
|
+
|
46
|
+
def failure_message_when_negated
|
47
|
+
"Expected `#{link_rel}` link to be absent"
|
48
|
+
end
|
49
|
+
alias_method :failure_message_for_should_not, :failure_message_when_negated
|
50
|
+
|
51
|
+
def description
|
52
|
+
"have #{link_rel} link or embedded"
|
53
|
+
end
|
54
|
+
|
55
|
+
def with_href(expected)
|
56
|
+
self.class.new(link_rel, tmpl_vars, matcherize(expected))
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
attr_reader :link_rel, :expected, :tmpl_vars
|
62
|
+
|
63
|
+
def hashish?(obj)
|
64
|
+
obj.respond_to?(:key?) && obj.respond_to?(:[])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -8,7 +8,9 @@ module RSpec
|
|
8
8
|
# expect(doc).to have_templated_relation("search", matching("{?q}"))
|
9
9
|
#
|
10
10
|
class TemplatedRelationMatcher
|
11
|
-
|
11
|
+
include HalMatcherHelpers
|
12
|
+
|
13
|
+
def initialize(link_rel, expected=NullMatcher)
|
12
14
|
@link_rel = link_rel
|
13
15
|
@expected = expected
|
14
16
|
end
|
@@ -37,15 +39,8 @@ module RSpec
|
|
37
39
|
else
|
38
40
|
"found none"
|
39
41
|
end
|
40
|
-
expected_clause = if expected != NullMatcher && expected.respond_to?(:description)
|
41
|
-
expected.description
|
42
|
-
elsif expected != NullMatcher
|
43
|
-
"matching #{expected}"
|
44
|
-
else
|
45
|
-
"to exist"
|
46
|
-
end
|
47
42
|
|
48
|
-
"Expected templated `#{link_rel}` link
|
43
|
+
sentencize "Expected templated `#{link_rel}` link", expected.description, "but #{but_clause}"
|
49
44
|
end
|
50
45
|
alias_method :failure_message_for_should, :failure_message
|
51
46
|
|
@@ -60,27 +55,7 @@ module RSpec
|
|
60
55
|
|
61
56
|
protected
|
62
57
|
|
63
|
-
attr_reader :link_rel, :outcome
|
64
|
-
|
65
|
-
NullMatcher = ->(_url_template){ true }
|
66
|
-
|
67
|
-
def expected
|
68
|
-
@expected ||= NullMatcher
|
69
|
-
end
|
70
|
-
|
71
|
-
def parse(jsonish)
|
72
|
-
json = if jsonish.kind_of? String
|
73
|
-
jsonish
|
74
|
-
|
75
|
-
elsif jsonish.respond_to? :to_hal
|
76
|
-
jsonish.to_hal
|
77
|
-
|
78
|
-
else jsonish.respond_to? :to_json
|
79
|
-
jsonish.to_json
|
80
|
-
end
|
81
|
-
|
82
|
-
HalClient::Representation.new(parsed_json: MultiJson.load(json))
|
83
|
-
end
|
58
|
+
attr_reader :link_rel, :outcome, :expected
|
84
59
|
end
|
85
60
|
end
|
86
61
|
end
|
data/lib/rspec/hal/version.rb
CHANGED
@@ -0,0 +1,126 @@
|
|
1
|
+
require_relative "../../../spec_helper"
|
2
|
+
require "rspec/version"
|
3
|
+
|
4
|
+
describe RSpec::Hal::Matchers::HavePropertyMatcher do
|
5
|
+
describe "creation" do
|
6
|
+
specify { expect{ described_class.new(a_prop_name) }.not_to raise_error }
|
7
|
+
specify { expect{ described_class.new(a_prop_name, any_matcher) }.not_to raise_error }
|
8
|
+
end
|
9
|
+
|
10
|
+
subject(:matcher) { described_class.new(a_prop_name) }
|
11
|
+
|
12
|
+
specify { expect(matcher.matches?(json_str_w_property)).to be_truthy}
|
13
|
+
specify { expect(matcher.matches?(json_str_wo_property)).to be_falsey}
|
14
|
+
|
15
|
+
specify { expect(matcher.matches?(parsed_json_w_property)).to be_truthy}
|
16
|
+
specify { expect(matcher.matches?(parsed_json_wo_property)).to be_falsey}
|
17
|
+
|
18
|
+
specify { expect(matcher.matches?(to_halable_w_property)).to be_truthy}
|
19
|
+
specify { expect(matcher.matches?(to_halable_wo_property)).to be_falsey}
|
20
|
+
|
21
|
+
|
22
|
+
describe "value expectation set via #matching(regexp)" do
|
23
|
+
subject(:matcher) { described_class.new(a_prop_name).matching(/ice$/) }
|
24
|
+
|
25
|
+
specify { expect(matcher.description).to match /have property `name`/ }
|
26
|
+
specify { expect(matcher.description).to match /match.*ice/ }
|
27
|
+
|
28
|
+
specify { expect(matcher.matches?(json_str_w_property)).to be_truthy}
|
29
|
+
specify { expect(matcher.matches?(json_str_wo_property)).to be_falsey}
|
30
|
+
specify { expect(matcher.matches?(json_str_w_nonmatching_property)).to be_falsey}
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "value expectation set via #matching(another_matcher)" do
|
34
|
+
subject(:matcher) { described_class.new(a_prop_name)
|
35
|
+
.matching(RSpec::Matchers::BuiltIn::EndWith.new("ice")) }
|
36
|
+
|
37
|
+
specify { expect(matcher.description).to match /have property `name`/ }
|
38
|
+
specify { expect(matcher.description).to match /end with.*/ }
|
39
|
+
|
40
|
+
specify { expect(matcher.matches?(json_str_w_property)).to be_truthy}
|
41
|
+
specify { expect(matcher.matches?(json_str_wo_property)).to be_falsey}
|
42
|
+
specify { expect(matcher.matches?(json_str_w_nonmatching_property)).to be_falsey}
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "value expectation set via #including(another_matcher)" do
|
46
|
+
subject(:matcher) { described_class.new('hobbies')
|
47
|
+
.including(RSpec::Matchers::BuiltIn::Include.new('type' => 'sport')) }
|
48
|
+
|
49
|
+
specify { expect(matcher.description).to match /have property `hobbies`/ }
|
50
|
+
specify { expect(matcher.description).to match /include.*sport/ }
|
51
|
+
|
52
|
+
specify { expect(matcher.matches?(json_str_w_property)).to be_truthy}
|
53
|
+
specify { expect(matcher.matches?(json_str_wo_property)).to be_falsey}
|
54
|
+
specify { expect(matcher.matches?(json_str_w_nonmatching_property)).to be_falsey}
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "value expectation set via #that_is(another_matcher)" do
|
58
|
+
subject(:matcher) { described_class.new(a_prop_name)
|
59
|
+
.that_is(RSpec::Matchers::BuiltIn::EndWith.new("ice")) }
|
60
|
+
|
61
|
+
specify { expect(matcher.description).to match /have property `name`/ }
|
62
|
+
specify { expect(matcher.description).to match /end with.*/ }
|
63
|
+
|
64
|
+
specify { expect(matcher.matches?(json_str_w_property)).to be_truthy}
|
65
|
+
specify { expect(matcher.matches?(json_str_wo_property)).to be_falsey}
|
66
|
+
specify { expect(matcher.matches?(json_str_w_nonmatching_property)).to be_falsey}
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "value expectation set via #that_is(exact_value)" do
|
70
|
+
subject(:matcher) { described_class.new(a_prop_name)
|
71
|
+
.that_is("Alice") }
|
72
|
+
|
73
|
+
specify { expect(matcher.description).to match /have property `name`/ }
|
74
|
+
specify { expect(matcher.description).to match /Alice/ }
|
75
|
+
|
76
|
+
specify { expect(matcher.matches?(json_str_w_property)).to be_truthy}
|
77
|
+
specify { expect(matcher.matches?(json_str_wo_property)).to be_falsey}
|
78
|
+
specify { expect(matcher.matches?(json_str_w_nonmatching_property)).to be_falsey}
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
specify { expect(matcher.description).to match "have property `#{a_prop_name}`" }
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
# Background
|
87
|
+
# ---
|
88
|
+
|
89
|
+
let(:json_str_w_property) { <<-HAL }
|
90
|
+
{ "name": "Alice"
|
91
|
+
,"hobbies": [{"name": "soccer", "type": "sport"}]
|
92
|
+
}
|
93
|
+
HAL
|
94
|
+
|
95
|
+
let(:json_str_wo_property) { <<-HAL }
|
96
|
+
{ }
|
97
|
+
HAL
|
98
|
+
|
99
|
+
let(:json_str_w_nonmatching_property) { <<-HAL }
|
100
|
+
{ "name": "Bob"
|
101
|
+
,"hobbies": [{"name": "trumpet", "type": "music"}] }
|
102
|
+
HAL
|
103
|
+
|
104
|
+
|
105
|
+
let(:parsed_json_w_property) { MultiJson.load json_str_w_property }
|
106
|
+
let(:parsed_json_wo_property) { MultiJson.load json_str_wo_property }
|
107
|
+
|
108
|
+
let(:to_halable_w_property) { halable.new json_str_w_property}
|
109
|
+
let(:to_halable_wo_property) { halable.new json_str_wo_property }
|
110
|
+
|
111
|
+
let(:halable) { Class.new do
|
112
|
+
def initialize(json)
|
113
|
+
@json = json
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_hal
|
117
|
+
return @json
|
118
|
+
end
|
119
|
+
end }
|
120
|
+
|
121
|
+
let(:a_prop_name) { "name" }
|
122
|
+
|
123
|
+
let(:any_matcher) { matching_prop_value_matcher }
|
124
|
+
let(:matching_prop_value_matcher) { match "Alice" }
|
125
|
+
# let(:nonmatching_template_str_matcher) { match "hello" }
|
126
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require_relative "../../../spec_helper"
|
2
|
+
|
3
|
+
describe RSpec::Hal::Matchers::RelationMatcher do
|
4
|
+
describe "creation" do
|
5
|
+
specify { expect{ described_class.new(a_link_rel) }.not_to raise_error }
|
6
|
+
specify { expect{ described_class.new(a_link_rel, any_href_matcher) }.not_to raise_error }
|
7
|
+
specify { expect{ described_class.new(a_link_rel, template_variables, any_href_matcher) }
|
8
|
+
.not_to raise_error }
|
9
|
+
end
|
10
|
+
|
11
|
+
subject(:matcher) { described_class.new(a_link_rel) }
|
12
|
+
|
13
|
+
specify{ expect(matcher.matches?(json_str_w_link)).to be_truthy }
|
14
|
+
specify{ expect(matcher.matches?(json_str_wo_link)).to be_falsey }
|
15
|
+
|
16
|
+
context "curries" do
|
17
|
+
let(:a_link_rel) { "http://example.com/rels/foo" }
|
18
|
+
specify{ expect(matcher.matches?(json_str_w_curied_link)).to be_truthy }
|
19
|
+
|
20
|
+
context "trying to match unexpanded rel" do
|
21
|
+
let(:a_link_rel) { "ex:foo" }
|
22
|
+
specify{ expect(matcher.matches? json_str_w_curied_link).to be_falsey }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "templated links" do
|
27
|
+
subject(:matcher) { described_class.new(a_link_rel, which: "mother") }
|
28
|
+
|
29
|
+
specify{ expect(matcher.matches? json_str_w_templated_link).to be_truthy }
|
30
|
+
specify{ expect(matcher.matches? json_str_w_link).to be_truthy }
|
31
|
+
specify{ expect(matcher.matches? json_str_wo_link).to be_falsey }
|
32
|
+
end
|
33
|
+
|
34
|
+
context "templated links with href matcher" do
|
35
|
+
subject(:matcher) { described_class.new(a_link_rel, {which: "mother"}, match(/parent/)) }
|
36
|
+
|
37
|
+
specify{ expect(matcher.matches? json_str_w_templated_link).to be_truthy }
|
38
|
+
specify{ expect(matcher.matches? json_str_w_link).to be_truthy }
|
39
|
+
specify{ expect(matcher.matches? json_str_wo_link).to be_falsey }
|
40
|
+
end
|
41
|
+
|
42
|
+
specify{ expect(matcher.matches?(parsed_json_w_link)).to be_truthy }
|
43
|
+
specify{ expect(matcher.matches?(parsed_json_wo_link)).to be_falsey }
|
44
|
+
|
45
|
+
specify{ expect(matcher.matches?(to_halable_w_link)).to be_truthy }
|
46
|
+
specify{ expect(matcher.matches?(to_halable_wo_link)).to be_falsey }
|
47
|
+
|
48
|
+
specify { expect(matcher.description).to match "have #{a_link_rel} link" }
|
49
|
+
|
50
|
+
context "exact expected href specified via #with_href" do
|
51
|
+
subject(:matcher) { described_class.new(a_link_rel)
|
52
|
+
.with_href("http://example.com/parent") }
|
53
|
+
|
54
|
+
specify{ expect(matcher.matches? json_str_w_link).to be_truthy }
|
55
|
+
specify{ expect(matcher.matches? json_str_wo_link).to be_falsey }
|
56
|
+
end
|
57
|
+
|
58
|
+
context "regexp expected href specified via #with_href" do
|
59
|
+
subject(:matcher) { described_class.new(a_link_rel)
|
60
|
+
.with_href(%r(/parent)) }
|
61
|
+
|
62
|
+
specify{ expect(matcher.matches? json_str_w_link).to be_truthy }
|
63
|
+
specify{ expect(matcher.matches? json_str_wo_link).to be_falsey }
|
64
|
+
end
|
65
|
+
|
66
|
+
context "matcher for expected href specified via #with_href" do
|
67
|
+
subject(:matcher) { described_class.new(a_link_rel)
|
68
|
+
.with_href(end_with("parent")) }
|
69
|
+
|
70
|
+
specify{ expect(matcher.matches? json_str_w_link).to be_truthy }
|
71
|
+
specify{ expect(matcher.matches? json_str_wo_link).to be_falsey }
|
72
|
+
end
|
73
|
+
|
74
|
+
context "non-matching expected href specified via #with_href" do
|
75
|
+
subject(:matcher) { described_class.new(a_link_rel)
|
76
|
+
.with_href("Malory") }
|
77
|
+
|
78
|
+
specify{ expect(matcher.matches? json_str_w_link).to be_falsy }
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
context "failed due to missing relation matcher" do
|
83
|
+
before do
|
84
|
+
matcher.matches? json_str_wo_link
|
85
|
+
end
|
86
|
+
|
87
|
+
specify { expect(matcher.failure_message)
|
88
|
+
.to match "Expected `#{a_link_rel}` link or embedded but found none" }
|
89
|
+
specify { expect(matcher.failure_message_for_should)
|
90
|
+
.to match matcher.failure_message }
|
91
|
+
end
|
92
|
+
|
93
|
+
context "failed due to unexpected existing relation" do
|
94
|
+
before do
|
95
|
+
matcher.matches? json_str_w_link
|
96
|
+
end
|
97
|
+
|
98
|
+
specify { expect(matcher.failure_message_when_negated)
|
99
|
+
.to match "Expected `#{a_link_rel}` link to be absent" }
|
100
|
+
specify { expect(matcher.failure_message_for_should_not)
|
101
|
+
.to match matcher.failure_message_when_negated }
|
102
|
+
end
|
103
|
+
|
104
|
+
context "failed due to sub-matcher failure matcher" do
|
105
|
+
subject(:matcher) { described_class.new(a_link_rel, match("absent")) }
|
106
|
+
before do
|
107
|
+
matcher.matches? json_str_wo_link
|
108
|
+
end
|
109
|
+
|
110
|
+
specify { expect(matcher.failure_message)
|
111
|
+
.to match %r(Expected `#{a_link_rel}` link or embedded match(?:ing)? "absent" but found none) }
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
# Background
|
116
|
+
# ---
|
117
|
+
|
118
|
+
let(:json_str_w_link) { <<-HAL }
|
119
|
+
{ "_links": {
|
120
|
+
"up": {"href": "http://example.com/parent"}
|
121
|
+
}}
|
122
|
+
HAL
|
123
|
+
|
124
|
+
let(:json_str_wo_link) { <<-HAL }
|
125
|
+
{ "_links": {
|
126
|
+
}}
|
127
|
+
HAL
|
128
|
+
|
129
|
+
let(:json_str_w_curied_link) { <<-HAL }
|
130
|
+
{ "_links": {
|
131
|
+
"ex:foo": {"href": "http://example.com/parent"},
|
132
|
+
"curies": [
|
133
|
+
{"name": "ex", "href": "http://example.com/rels/{rel}", "templated": true }
|
134
|
+
]
|
135
|
+
}}
|
136
|
+
HAL
|
137
|
+
|
138
|
+
let(:json_str_w_templated_link) { <<-HAL }
|
139
|
+
{ "_links": {
|
140
|
+
"up": {"href": "http://example.com/parent{?which}", "templated": true}
|
141
|
+
}}
|
142
|
+
HAL
|
143
|
+
|
144
|
+
|
145
|
+
# let(:json_str_w_nontemplate_link) { <<-HAL }
|
146
|
+
# { "_links": {
|
147
|
+
# "up": {"href": "http://example.com/parent"}
|
148
|
+
# }}
|
149
|
+
# HAL
|
150
|
+
|
151
|
+
|
152
|
+
let(:parsed_json_w_link) { MultiJson.load json_str_w_link }
|
153
|
+
let(:parsed_json_wo_link) { MultiJson.load json_str_wo_link }
|
154
|
+
|
155
|
+
let(:to_halable_w_link) { halable.new json_str_w_link}
|
156
|
+
let(:to_halable_wo_link) { halable.new json_str_wo_link }
|
157
|
+
|
158
|
+
let(:halable) { Class.new do
|
159
|
+
def initialize(json)
|
160
|
+
@json = json
|
161
|
+
end
|
162
|
+
|
163
|
+
def to_hal
|
164
|
+
return @json
|
165
|
+
end
|
166
|
+
end }
|
167
|
+
|
168
|
+
let(:a_link_rel) { "up" }
|
169
|
+
let(:any_href_matcher) { matching_href_matcher }
|
170
|
+
let(:matching_href_matcher) { match /example.com/ }
|
171
|
+
let(:nonmatching_href_matcher) { match "hello" }
|
172
|
+
let(:template_variables) { {q: "search terms"} }
|
173
|
+
end
|
@@ -28,7 +28,7 @@ describe RSpec::Hal::Matchers::TemplatedRelationMatcher do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
specify { expect(matcher.failure_message)
|
31
|
-
.to match "Expected templated `#{a_link_rel}` link
|
31
|
+
.to match "Expected templated `#{a_link_rel}` link but found none" }
|
32
32
|
specify { expect(matcher.failure_message_for_should)
|
33
33
|
.to match matcher.failure_message }
|
34
34
|
end
|
@@ -50,17 +50,17 @@ describe RSpec::Hal::Matchers::TemplatedRelationMatcher do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
specify { expect(matcher.failure_message)
|
53
|
-
.to match "Expected templated `#{a_link_rel}` link
|
53
|
+
.to match "Expected templated `#{a_link_rel}` link but found only non-templated links" }
|
54
54
|
end
|
55
55
|
|
56
56
|
context "failed due to sub-matcher failure matcher" do
|
57
|
-
subject(:matcher) { described_class.new(a_link_rel,
|
57
|
+
subject(:matcher) { described_class.new(a_link_rel, match("absent")) }
|
58
58
|
before do
|
59
59
|
matcher.matches? json_str_wo_link
|
60
60
|
end
|
61
61
|
|
62
62
|
specify { expect(matcher.failure_message)
|
63
|
-
.to match %(Expected templated `#{a_link_rel}` link
|
63
|
+
.to match %r(Expected templated `#{a_link_rel}` link match(?:ing)? "absent" but found none) }
|
64
64
|
end
|
65
65
|
|
66
66
|
|
@@ -17,7 +17,7 @@ describe RSpec::Hal::Matchers do
|
|
17
17
|
|
18
18
|
matcher :be_a_matcher do
|
19
19
|
match do |actual|
|
20
|
-
respond_to?(:matches?) && respond_to?(:failure_message)
|
20
|
+
actual.respond_to?(:matches?) && actual.respond_to?(:failure_message)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -38,50 +38,6 @@ describe RSpec::Hal::Matchers::Document do
|
|
38
38
|
specify { expect(matcher.matches?(hal_doc)).to be_falsey }
|
39
39
|
end
|
40
40
|
|
41
|
-
describe "have_property('name')" do
|
42
|
-
subject(:matcher) { have_property('name') }
|
43
|
-
|
44
|
-
specify { expect(matcher.matches?(hal_doc)).to be_truthy}
|
45
|
-
specify { expect(matcher.matches?("{}")).to be_falsey}
|
46
|
-
end
|
47
|
-
|
48
|
-
describe "have_property('name').matching(/ice$/)" do
|
49
|
-
subject(:matcher) { have_property('name').matching(/ice$/) }
|
50
|
-
|
51
|
-
specify { expect(matcher.matches?(hal_doc)).to be_truthy}
|
52
|
-
specify { expect(matcher.matches?("{}")).to be_falsey}
|
53
|
-
specify { expect(matcher.matches?(bob)).to be_falsey}
|
54
|
-
end
|
55
|
-
|
56
|
-
describe "have_property('name').matching(end_with('ice'))" do
|
57
|
-
before do skip("RSpec 3 feature") unless /3\./ === RSpec::Version::STRING end
|
58
|
-
subject(:matcher) { have_property('name')
|
59
|
-
.matching(RSpec::Matchers::BuiltIn::EndWith.new("ice")) }
|
60
|
-
|
61
|
-
specify { expect(matcher.matches?(hal_doc)).to be_truthy}
|
62
|
-
specify { expect(matcher.matches?("{}")).to be_falsey}
|
63
|
-
specify { expect(matcher.matches?(bob)).to be_falsey}
|
64
|
-
end
|
65
|
-
|
66
|
-
describe "have_property('hobbies').including(a_hash_including('type' => 'sport'))" do
|
67
|
-
subject(:matcher) { have_property('hobbies')
|
68
|
-
.including(RSpec::Matchers::BuiltIn::Include.new('type' => 'sport')) }
|
69
|
-
before do extend described_class end
|
70
|
-
|
71
|
-
specify { expect(matcher.matches?(hal_doc)).to be_truthy}
|
72
|
-
specify { expect(matcher.matches?("{}")).to be_falsey}
|
73
|
-
specify { expect(matcher.matches?(bob)).to be_falsey}
|
74
|
-
end
|
75
|
-
|
76
|
-
describe "have_relation('tag')" do
|
77
|
-
subject(:matcher) { have_relation('tag') }
|
78
|
-
|
79
|
-
specify { expect(matcher.matches?(hal_doc)).to be_truthy}
|
80
|
-
specify { expect(matcher.matches?("{}")).to be_falsey}
|
81
|
-
specify { expect(matcher.matches?(bob)).to be_falsey}
|
82
|
-
end
|
83
|
-
|
84
|
-
|
85
41
|
before do
|
86
42
|
extend RSpec::Hal::Matchers::Document
|
87
43
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-hal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -88,9 +88,14 @@ files:
|
|
88
88
|
- lib/rspec-hal.rb
|
89
89
|
- lib/rspec/hal.rb
|
90
90
|
- lib/rspec/hal/matchers.rb
|
91
|
+
- lib/rspec/hal/matchers/hal_matcher_helpers.rb
|
92
|
+
- lib/rspec/hal/matchers/have_property_matcher.rb
|
93
|
+
- lib/rspec/hal/matchers/relation_matcher.rb
|
91
94
|
- lib/rspec/hal/matchers/templated_relation_matcher.rb
|
92
95
|
- lib/rspec/hal/version.rb
|
93
96
|
- rspec-hal.gemspec
|
97
|
+
- spec/rspec/hal/matchers/have_property_matcher_spec.rb
|
98
|
+
- spec/rspec/hal/matchers/relation_matcher_spec.rb
|
94
99
|
- spec/rspec/hal/matchers/templated_relation_matcher_spec.rb
|
95
100
|
- spec/rspec/hal/matchers_spec.rb
|
96
101
|
- spec/spec_helper.rb
|
@@ -119,6 +124,8 @@ signing_key:
|
|
119
124
|
specification_version: 4
|
120
125
|
summary: Matchers and helpers for specing HAL documents.
|
121
126
|
test_files:
|
127
|
+
- spec/rspec/hal/matchers/have_property_matcher_spec.rb
|
128
|
+
- spec/rspec/hal/matchers/relation_matcher_spec.rb
|
122
129
|
- spec/rspec/hal/matchers/templated_relation_matcher_spec.rb
|
123
130
|
- spec/rspec/hal/matchers_spec.rb
|
124
131
|
- spec/spec_helper.rb
|