rspec-hal 1.2.0 → 1.2.1
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/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
|