brine-dsl 0.9.0 → 0.10.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/Gemfile.lock +1 -1
- data/Rakefile +1 -1
- data/brine-dsl.gemspec +1 -2
- data/lib/brine/cleaning_up.rb +120 -0
- data/lib/brine/client_building.rb +123 -0
- data/lib/brine/coercing.rb +91 -0
- data/lib/brine/hooks.rb +8 -1
- data/lib/brine/mustache_expanding.rb +51 -0
- data/lib/brine/performing.rb +159 -0
- data/lib/brine/requesting.rb +171 -0
- data/lib/brine/rest_steps.rb +1 -1
- data/lib/brine/selecting.rb +166 -0
- data/lib/brine/step_definitions/assertions.rb +15 -15
- data/lib/brine/step_definitions/assignment.rb +5 -4
- data/lib/brine/step_definitions/cleanup.rb +2 -2
- data/lib/brine/step_definitions/perform.rb +16 -0
- data/lib/brine/step_definitions/request_construction.rb +12 -8
- data/lib/brine/step_definitions/selection.rb +24 -12
- data/lib/brine/test_steps.rb +20 -0
- data/lib/brine/transforms.rb +12 -4
- data/lib/brine/type_checking.rb +88 -0
- data/lib/brine/util.rb +1 -0
- data/lib/brine.rb +13 -20
- metadata +12 -9
- data/lib/brine/cleaner_upper.rb +0 -101
- data/lib/brine/coercer.rb +0 -68
- data/lib/brine/mustache_binder.rb +0 -25
- data/lib/brine/requester.rb +0 -161
- data/lib/brine/selector.rb +0 -66
- data/lib/brine/type_checks.rb +0 -36
@@ -0,0 +1,171 @@
|
|
1
|
+
##
|
2
|
+
# @file requesting.rb
|
3
|
+
# Request construction and response storage.
|
4
|
+
##
|
5
|
+
|
6
|
+
module Brine
|
7
|
+
|
8
|
+
##
|
9
|
+
# Module in charge of constructing requests and saving responses.
|
10
|
+
##
|
11
|
+
module Requesting
|
12
|
+
require 'faraday_middleware'
|
13
|
+
require 'brine/client_building'
|
14
|
+
|
15
|
+
##
|
16
|
+
# The root url to which Brine will send requests.
|
17
|
+
#
|
18
|
+
# This will normally be the value of ENV['BRINE_ROOT_URL'],
|
19
|
+
# and that value should be directly usable after older
|
20
|
+
# ENV['ROOT_URL'] is end-of-lifed (at which point this can be removed).
|
21
|
+
#
|
22
|
+
# @brine_root_url is used if set to allow setting this value more programmatically.
|
23
|
+
#
|
24
|
+
# @return [String] The root URL to use or nil if none is provided.
|
25
|
+
##
|
26
|
+
def brine_root_url
|
27
|
+
if @brine_root_url
|
28
|
+
@brine_root_url
|
29
|
+
elsif ENV['BRINE_ROOT_URL']
|
30
|
+
ENV['BRINE_ROOT_URL']
|
31
|
+
elsif ENV['ROOT_URL']
|
32
|
+
deprecation_message('1.0', 'ROOT_URL is deprecated, replace with BRINE_ROOT_URL') if ENV['ROOT_URL']
|
33
|
+
ENV['ROOT_URL']
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Normalize an HTTP method for the HTTP client library (to a lowercased symbol).
|
39
|
+
#
|
40
|
+
# @param [String] method A text representation of the HTTP method.
|
41
|
+
# @return [Symbol] A representation of `method` usable by the HTTP client library.
|
42
|
+
##
|
43
|
+
def parse_method(method)
|
44
|
+
method.downcase.to_sym
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Set the client which will be used to send HTTP requests.
|
49
|
+
#
|
50
|
+
# This will generally be a connection as created by the ClientBuilding module.
|
51
|
+
#
|
52
|
+
# @param [Faraday::Connection, #run_request] client The client which will be used to issue HTTP requests.
|
53
|
+
##
|
54
|
+
def set_client(client)
|
55
|
+
@client = client
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# The currently active client which will be used to issue HTTP calls.
|
60
|
+
#
|
61
|
+
# This will be initialized as neded on first access
|
62
|
+
# to a default client constructed by the ClientBuilding module.
|
63
|
+
#
|
64
|
+
# @return [Faraday::Connection, #run_request] The currently active client object.
|
65
|
+
##
|
66
|
+
def client
|
67
|
+
@client ||= client_for_host(brine_root_url)
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Clear any previously built request state and set defaults.
|
72
|
+
#
|
73
|
+
# This should be called upon request completion or when constructing a new
|
74
|
+
# request so no extant state inadvertently pollutes the new construction.
|
75
|
+
##
|
76
|
+
def reset_request
|
77
|
+
@params = @headers = @body = nil
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Store the provided body in the request being built.
|
82
|
+
#
|
83
|
+
# This will override any previous body value.
|
84
|
+
#
|
85
|
+
# @param [Object] The new data to be placed in the request body.
|
86
|
+
##
|
87
|
+
def set_request_body(obj)
|
88
|
+
@body = obj
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# Send a `method` request to `url` including any current builder options and store response.
|
93
|
+
#
|
94
|
+
# The response will be available as the `#response` property.
|
95
|
+
#
|
96
|
+
# For requests such as simple GETs that only require a url this method may
|
97
|
+
# be self-contained; for more complex requests the values collected through
|
98
|
+
# request building are likely required. Any data present from the builder
|
99
|
+
# methods will always be inclued in the request and therefore such data should
|
100
|
+
# be cleared using `#reset_request` if it is not desired.
|
101
|
+
#
|
102
|
+
# @param [Symbol] method The client friendly representation of the HTTP method for the request
|
103
|
+
# (@see #parse_method).
|
104
|
+
# @param [String] url The url to which the request will be sent.
|
105
|
+
##
|
106
|
+
def send_request(method, url)
|
107
|
+
@response = client.run_request(method, url, @body, headers) do |req|
|
108
|
+
req.params = request_params
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# The response for the last sent request.
|
114
|
+
#
|
115
|
+
# @return [Faraday::Response] The most recent response.
|
116
|
+
##
|
117
|
+
def response
|
118
|
+
@response
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# The headers for the request currently being built.
|
123
|
+
#
|
124
|
+
# Will be initialized as needed on first access,
|
125
|
+
# with a default specifying JSON content-type.
|
126
|
+
#
|
127
|
+
# @return [Hash] The headers to use for the constructed request.
|
128
|
+
##
|
129
|
+
def headers
|
130
|
+
@headers ||= {content_type: 'application/json'}
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# Set the specified header to the provided value.
|
135
|
+
#
|
136
|
+
# @param [String] k The name of the header whose value will be set.
|
137
|
+
# @param [Object] v The value to set for the specified header.
|
138
|
+
# This should normally be a String, but some other types may work.
|
139
|
+
##
|
140
|
+
def set_header(k, v)
|
141
|
+
headers[k] = v
|
142
|
+
end
|
143
|
+
|
144
|
+
##
|
145
|
+
# The query parameters which will be attached to the constructeed request.
|
146
|
+
#
|
147
|
+
# Will be initialized to an empty hash as needed upon first access.
|
148
|
+
#
|
149
|
+
# @return [Hash] The query parameters to use for request construction.
|
150
|
+
##
|
151
|
+
def request_params
|
152
|
+
@request_params ||= {}
|
153
|
+
end
|
154
|
+
|
155
|
+
##
|
156
|
+
# Assign the provided value to the specified request query parameter.
|
157
|
+
#
|
158
|
+
# @param [String] k The name of the query parameter whose value is being assigned.
|
159
|
+
# @param [Object] v The value to assign the query parameter (normally a String).
|
160
|
+
##
|
161
|
+
def set_request_param(k, v)
|
162
|
+
request_params[k] = v
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Mix the Requesting module functionality into the main Brine module.
|
169
|
+
##
|
170
|
+
include Requesting
|
171
|
+
end
|
data/lib/brine/rest_steps.rb
CHANGED
@@ -0,0 +1,166 @@
|
|
1
|
+
##
|
2
|
+
# @file selecting.rb
|
3
|
+
# Selection of one or more values to be used by Brine (normally for assertion).
|
4
|
+
##
|
5
|
+
|
6
|
+
module Brine
|
7
|
+
|
8
|
+
##
|
9
|
+
# A module providing assorted means to select particular values out of objects/graphs.
|
10
|
+
##
|
11
|
+
module Selecting
|
12
|
+
|
13
|
+
require 'brine/coercing'
|
14
|
+
require 'rspec/expectations'
|
15
|
+
require 'jsonpath'
|
16
|
+
|
17
|
+
##
|
18
|
+
# An object responsible for selecting one or more values.
|
19
|
+
# This Selector will test whether the targeted value itself satisfies the assertion.
|
20
|
+
#
|
21
|
+
# RSpec is used within this implementation to perform assertions.
|
22
|
+
# The Selector ultimately perform this assertion by accepting an RSpec matcher
|
23
|
+
# which it applied against the targeted value.
|
24
|
+
##
|
25
|
+
class Selector
|
26
|
+
include RSpec::Matchers
|
27
|
+
|
28
|
+
##
|
29
|
+
# [Coercer] The Coercer that may modify values prior to performing assertions.
|
30
|
+
##
|
31
|
+
attr_accessor :coercer
|
32
|
+
|
33
|
+
##
|
34
|
+
# Construct a selector to perform assertions against a provided target.
|
35
|
+
#
|
36
|
+
# @param [Object] taret The value against which assertions will be performed.
|
37
|
+
# @param [Boolean] negated Whether the assertions from this selector should be negated.
|
38
|
+
# This is deprecated and should instead be passed to #assert_that.
|
39
|
+
##
|
40
|
+
def initialize(target, negated=false)
|
41
|
+
@target = target
|
42
|
+
@negated = negated
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Optionally perform some modification to the RSpec matcher prior to assertion.
|
47
|
+
#
|
48
|
+
# This is designed to allow subclassess to be able to modify the way
|
49
|
+
# in which matchers are applied against the values. This method is a pass-through in this class.
|
50
|
+
#
|
51
|
+
# @param [RSpec::Matcher] matcher The matcher originally passed to #assert_that.
|
52
|
+
# @return [RSpec::Matcher] The Matcher to be used while performing the assertion.
|
53
|
+
##
|
54
|
+
def filter_matcher(matcher)
|
55
|
+
matcher
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Perform the provided assertion against the instance target.
|
60
|
+
#
|
61
|
+
# The values will be coerced prior to evaluation.
|
62
|
+
#
|
63
|
+
# @param [Object] value The value/parameter against which the target will be compared.
|
64
|
+
# In cases where no parameter is needed for comparison, this may be nil.
|
65
|
+
# @param [Boolean] negated If true the assertion should be expected to _fail_, otherwise it should pass.
|
66
|
+
# @param [Block] A block which will be passed a coerced copy of `value` and which should return an
|
67
|
+
# RSpec matcher which will be evaluated against the coerced target value.
|
68
|
+
##
|
69
|
+
def assert_that(value, negated=nil)
|
70
|
+
# shim while moving negation to assertions.
|
71
|
+
negated = @negated if negated.nil?
|
72
|
+
target, value = coercer.coerce(@target, value)
|
73
|
+
message = negated ? :to_not : :to
|
74
|
+
matcher = filter_matcher(yield(value))
|
75
|
+
expect(target).send(message, matcher)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# A Selector which will test whether any of the children of the targeted value satisfy the assertion.
|
82
|
+
##
|
83
|
+
class AnySelector < Selector
|
84
|
+
def filter_matcher(matcher)
|
85
|
+
include(matcher)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# A Selector which will test whether all of the children of the targeted value satisfy the assertion.
|
91
|
+
##
|
92
|
+
class AllSelector < Selector
|
93
|
+
def filter_matcher(matcher)
|
94
|
+
all(matcher)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# Activate a Selector for the provided target.
|
100
|
+
#
|
101
|
+
# @param [Object] target The value which the Selector should target.
|
102
|
+
# @param [Boolean] negated DEPRECATED If true the assertions should be expected to fail.
|
103
|
+
##
|
104
|
+
def select(target, negated=nil)
|
105
|
+
use_selector(Selector.new(target, negated))
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# Activate a Selector for any of the children of the provided target.
|
110
|
+
#
|
111
|
+
# @param [Object] target The value which the Selector should target.
|
112
|
+
# @param [Boolean] negated DEPRECATED If true the assertions should be expected to fail.
|
113
|
+
##
|
114
|
+
def select_any(target, negated=nil)
|
115
|
+
use_selector(AnySelector.new(target, negated))
|
116
|
+
end
|
117
|
+
|
118
|
+
##
|
119
|
+
# Activate a Selector for all of the children of the provided target.
|
120
|
+
#
|
121
|
+
# @param [Object] target The value which the Selector should target.
|
122
|
+
# @param [Boolean] negated DEPRECATED If true the assertions should be expected to fail.
|
123
|
+
##
|
124
|
+
def select_all(target, negated=nil)
|
125
|
+
use_selector(AllSelector.new(target, negated))
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Configure selector and make it the active Selector.
|
130
|
+
#
|
131
|
+
# @param [Selector] selector The selector which will be activated.
|
132
|
+
##
|
133
|
+
def use_selector(selector)
|
134
|
+
selector.coercer = coercer
|
135
|
+
@selector = selector
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# The currently active Selector.
|
140
|
+
#
|
141
|
+
# @return The Selector as set by #use_selector
|
142
|
+
##
|
143
|
+
def selector
|
144
|
+
@selector
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
# Mix the Selecting module functionality into the main Brine module.
|
150
|
+
include Selecting
|
151
|
+
end
|
152
|
+
|
153
|
+
#
|
154
|
+
# Steps
|
155
|
+
#
|
156
|
+
RESPONSE_ATTRIBUTES='(status|headers|body)'
|
157
|
+
Then(/^the value of `([^`]*)` is( not)? (.*)$/) do |value, negated, assertion|
|
158
|
+
select(value, (!negated.nil?))
|
159
|
+
step "it is #{assertion}"
|
160
|
+
end
|
161
|
+
|
162
|
+
def dig_from_response(attribute, path=nil, plural=false)
|
163
|
+
root = response.send(attribute.to_sym)
|
164
|
+
return root if !path
|
165
|
+
JsonPath.new("$.#{path}").send(plural ? :on : :first, root)
|
166
|
+
end
|
@@ -1,50 +1,50 @@
|
|
1
1
|
# assertions.rb - General assertions to be used with a Selector
|
2
2
|
|
3
3
|
Then(/^it is equal to `([^`]*)`$/) do |value|
|
4
|
-
selector.assert_that(value) {|v| eq v}
|
4
|
+
perform { selector.assert_that(value) {|v| eq v} }
|
5
5
|
end
|
6
6
|
Then(/^it is equal to:$/) do |value|
|
7
|
-
selector.assert_that(value) {|v| eq v}
|
7
|
+
perform { selector.assert_that(value) {|v| eq v} }
|
8
8
|
end
|
9
9
|
Then(/^it is matching `([^`]*)`$/) do |value|
|
10
|
-
selector.assert_that(value) {|v| match v}
|
10
|
+
perform { selector.assert_that(value) {|v| match v} }
|
11
11
|
end
|
12
12
|
Then (/^it is matching:$/) do |value|
|
13
|
-
selector.assert_that(value) {|v| match v}
|
13
|
+
perform { selector.assert_that(value) {|v| match v} }
|
14
14
|
end
|
15
15
|
Then(/^it is greater than `([^`]*)`$/) do |value|
|
16
|
-
selector.assert_that(value) {|v| be > v}
|
16
|
+
perform { selector.assert_that(value) {|v| be > v} }
|
17
17
|
end
|
18
18
|
Then(/^it is greater than or equal to `([^`]*)`$/) do |value|
|
19
|
-
selector.assert_that(value) {|v| be >= v}
|
19
|
+
perform { selector.assert_that(value) {|v| be >= v} }
|
20
20
|
end
|
21
21
|
Then(/^it is less than `([^`]*)`$/) do |value|
|
22
|
-
selector.assert_that(value) {|v| be < v}
|
22
|
+
perform { selector.assert_that(value) {|v| be < v} }
|
23
23
|
end
|
24
24
|
Then(/^it is less than or equal to `([^`]*)`$/) do |value|
|
25
|
-
selector.assert_that(value) {|v| be <= v}
|
25
|
+
perform { selector.assert_that(value) {|v| be <= v} }
|
26
26
|
end
|
27
27
|
|
28
28
|
# Be a little smarter than default.
|
29
29
|
Then(/^it is empty$/) do
|
30
|
-
selector.assert_that(nil) do
|
30
|
+
perform { selector.assert_that(nil) do
|
31
31
|
satisfy{|i| i.nil? || (i.respond_to?(:empty?) && i.empty?) }
|
32
|
-
end
|
32
|
+
end }
|
33
33
|
end
|
34
34
|
|
35
35
|
Then(/^it is including `([^`]*)`$/) do |value|
|
36
|
-
selector.assert_that(value) {|v| include v }
|
36
|
+
perform { selector.assert_that(value) {|v| include v } }
|
37
37
|
end
|
38
38
|
Then(/^it is including:$/) do |value|
|
39
|
-
selector.assert_that(value) {|v| include v }
|
39
|
+
perform { selector.assert_that(value) {|v| include v } }
|
40
40
|
end
|
41
41
|
|
42
42
|
Then(/^it is a valid `([^`]*)`$/) do |type|
|
43
|
-
selector.assert_that(type) {|t| type_check_for(t) }
|
43
|
+
perform { selector.assert_that(type) {|t| type_check_for(t) } }
|
44
44
|
end
|
45
45
|
|
46
46
|
Then(/^it is of length `([^`]*)`$/) do |length|
|
47
|
-
selector.assert_that(length) do |l|
|
47
|
+
perform { selector.assert_that(length) do |l|
|
48
48
|
satisfy{|i| i.respond_to?(:length) && i.length == l}
|
49
|
-
end
|
49
|
+
end }
|
50
50
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
##
|
2
2
|
# @file assignment.rb
|
3
3
|
# Assignment related steps.
|
4
|
+
##
|
4
5
|
|
5
6
|
##
|
6
7
|
# Assign the provided parameter.
|
@@ -8,7 +9,7 @@
|
|
8
9
|
# @param name - The identifier to which the value will be bound.
|
9
10
|
# @param value - The value to bind to the identifier.
|
10
11
|
When(/^`([^`]*)` is assigned `([^`]*)`$/) do |name, value|
|
11
|
-
bind(name, value)
|
12
|
+
perform { bind(name, value) }
|
12
13
|
end
|
13
14
|
|
14
15
|
##
|
@@ -16,7 +17,7 @@ end
|
|
16
17
|
#
|
17
18
|
# @param name - The identifier to which a random string will be bound.
|
18
19
|
When(/^`([^`]*)` is assigned a random string$/) do |name|
|
19
|
-
bind(name, SecureRandom.uuid)
|
20
|
+
perform { bind(name, SecureRandom.uuid) }
|
20
21
|
end
|
21
22
|
|
22
23
|
##
|
@@ -24,7 +25,7 @@ end
|
|
24
25
|
#
|
25
26
|
# @param name - The identifier to which the current timestamp will be bound.
|
26
27
|
When(/^`([^`]*)` is assigned a timestamp$/) do |name|
|
27
|
-
bind(name, DateTime.now)
|
28
|
+
perform { bind(name, DateTime.now) }
|
28
29
|
end
|
29
30
|
|
30
31
|
##
|
@@ -37,5 +38,5 @@ end
|
|
37
38
|
# whether to extract a single match or a collection of all matching.
|
38
39
|
When(/^`([^`]*)` is assigned the response #{RESPONSE_ATTRIBUTES}(?: child(ren)? `([^`]*)`)?$/) do
|
39
40
|
|name, attribute, plural, path|
|
40
|
-
bind(name, dig_from_response(attribute, path, !plural.nil?))
|
41
|
+
perform { bind(name, dig_from_response(attribute, path, !plural.nil?)) }
|
41
42
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
##
|
2
|
+
# @file perform.rb
|
3
|
+
# Steps related to performing actions
|
4
|
+
##
|
5
|
+
|
6
|
+
When /^actions are defined such that$/ do
|
7
|
+
collect_actions
|
8
|
+
end
|
9
|
+
|
10
|
+
Then /^the actions are( not)? successful within a `([^`]*)` period$/ do |negated, period|
|
11
|
+
method = negated ? :to : :to_not
|
12
|
+
expect { poll_for(retrieve_duration(period)) {
|
13
|
+
performer.evaluate
|
14
|
+
} }.send(method, raise_error)
|
15
|
+
reset_performer
|
16
|
+
end
|
@@ -1,24 +1,28 @@
|
|
1
1
|
# request_construction.rb - Build and send requests
|
2
2
|
|
3
3
|
When(/^the request body is assigned:$/) do |input|
|
4
|
-
set_request_body(input)
|
4
|
+
perform { set_request_body(input) }
|
5
5
|
end
|
6
6
|
|
7
7
|
When(/^the request query parameter `([^`]*)` is assigned `([^`]*)`$/) do |param, value|
|
8
|
-
|
8
|
+
perform { set_request_param(param, value) }
|
9
9
|
end
|
10
10
|
|
11
11
|
When(/^the request header `([^`]*)` is assigned `([^`]*)`$/) do |header, value|
|
12
|
-
|
12
|
+
perform { set_header(header, value) }
|
13
13
|
end
|
14
14
|
|
15
15
|
When(/^the request credentials are set for basic auth user `([^`]*)` and password `([^`]*)`$/) do |user, password|
|
16
|
-
|
17
|
-
|
16
|
+
perform do
|
17
|
+
base64_combined = Base64.strict_encode64("#{user}:#{password}")
|
18
|
+
set_header('Authorization', "Basic #{base64_combined}")
|
19
|
+
end
|
18
20
|
end
|
19
21
|
|
20
22
|
When(/^an? (GET|POST|PATCH|PUT|DELETE|HEAD|OPTIONS) is sent to `([^`]*)`$/) do |method, url|
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
perform do
|
24
|
+
send_request(parse_method(method), URI.escape(url))
|
25
|
+
bind('response', response)
|
26
|
+
reset_request
|
27
|
+
end
|
24
28
|
end
|
@@ -1,37 +1,49 @@
|
|
1
1
|
#RESPONSE_ATTRIBUTES='(status|headers|body)'
|
2
2
|
Then(/^the value of the response #{RESPONSE_ATTRIBUTES}(?: child(ren)? `([^`]*)`)? is( not)? (.*)(?<!:)$/) do
|
3
3
|
|attribute, plural, path, negated, assertion|
|
4
|
-
|
5
|
-
|
4
|
+
perform do
|
5
|
+
select(dig_from_response(attribute, path, !plural.nil?), (!negated.nil?))
|
6
|
+
step "it is #{assertion}"
|
7
|
+
end
|
6
8
|
end
|
7
9
|
|
8
10
|
Then(/^the value of the response #{RESPONSE_ATTRIBUTES}(?: child(ren)? `([^`]*)`)? is( not)? (.*)(?<=:)$/) do
|
9
11
|
|attribute, plural, path, negated, assertion, multi|
|
10
|
-
|
11
|
-
|
12
|
+
perform do
|
13
|
+
select(dig_from_response(attribute, path, !plural.nil?), (!negated.nil?))
|
14
|
+
step "it is #{assertion}", multi.to_json
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
18
|
Then(/^the value of the response #{RESPONSE_ATTRIBUTES}(?: child(ren)? `([^`]*)`)? does( not)? have any element that is (.*)(?<!:)$/) do
|
15
19
|
|attribute, plural, path, negated, assertion|
|
16
|
-
|
17
|
-
|
20
|
+
perform do
|
21
|
+
select_any(dig_from_response(attribute, path, !plural.nil?), (!negated.nil?))
|
22
|
+
step "it is #{assertion}"
|
23
|
+
end
|
18
24
|
end
|
19
25
|
|
20
26
|
Then(/^the value of the response #{RESPONSE_ATTRIBUTES}(?: child(ren)? `([^`]*)`)? does( not)? have any element that is (.*)(?<=:)$/) do
|
21
27
|
|attribute, plural, path, negated, assertion, multi|
|
22
|
-
|
23
|
-
|
28
|
+
perform do
|
29
|
+
select_any(dig_from_response(attribute, path, !plural.nil?), (!negated.nil?))
|
30
|
+
step "it is #{assertion}", multi.to_json
|
31
|
+
end
|
24
32
|
end
|
25
33
|
|
26
34
|
#Would be negated with `not all' which would be equivalent to any(not ) but that's not readily supported
|
27
35
|
Then(/^the value of the response #{RESPONSE_ATTRIBUTES}(?: child(ren)? `([^`]*)`)? has elements which are all (.*)(?<!:)$/) do
|
28
36
|
|attribute, plural, path, assertion|
|
29
|
-
|
30
|
-
|
37
|
+
perform do
|
38
|
+
select_all(dig_from_response(attribute, path, !plural.nil?), false)
|
39
|
+
step "it is #{assertion}"
|
40
|
+
end
|
31
41
|
end
|
32
42
|
|
33
43
|
Then(/^the value of the response #{RESPONSE_ATTRIBUTES}(?: child(ren)? `([^`]*)`)? has elements which are all (.*)(?<=:)$/) do
|
34
44
|
|attribute, plural, path, assertion, multi|
|
35
|
-
|
36
|
-
|
45
|
+
perform do
|
46
|
+
select_all(dig_from_response(attribute, path, !plural.nil?), false)
|
47
|
+
step "it is #{assertion}", multi.to_json
|
48
|
+
end
|
37
49
|
end
|
data/lib/brine/test_steps.rb
CHANGED
@@ -5,6 +5,9 @@ require 'rspec'
|
|
5
5
|
#
|
6
6
|
HTTP_METHOD='GET|POST|PATCH|PUT|DELETE|HEAD|OPTIONS'
|
7
7
|
|
8
|
+
ENV['BRINE_DURATION_SECONDS_short'] = '3'
|
9
|
+
ENV['BRINE_DURATION_SECONDS_long'] = '6'
|
10
|
+
|
8
11
|
class StubResponse
|
9
12
|
attr_accessor :body, :status, :headers
|
10
13
|
|
@@ -15,6 +18,19 @@ class StubResponse
|
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
21
|
+
class DelayedStubResponse < StubResponse
|
22
|
+
|
23
|
+
def initialize(delay)
|
24
|
+
super()
|
25
|
+
@activation = Time.now + delay
|
26
|
+
end
|
27
|
+
|
28
|
+
def body
|
29
|
+
Time.now < @activation ? nil : @body
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
18
34
|
class StubRequest
|
19
35
|
attr_accessor :method, :path, :headers, :body
|
20
36
|
|
@@ -135,6 +151,10 @@ When /^the response status is assigned `([^`]*)`$/ do |status|
|
|
135
151
|
@response.status = status.to_i # this coercion isn't needed but is a guarantee
|
136
152
|
end
|
137
153
|
|
154
|
+
When /^the response is delayed `([^`]*)` seconds$/ do |seconds|
|
155
|
+
@response = DelayedStubResponse.new(seconds)
|
156
|
+
end
|
157
|
+
|
138
158
|
Then(/^the response body as JSON is:$/) do |text|
|
139
159
|
expect(response.body.to_json).to eq text
|
140
160
|
end
|
data/lib/brine/transforms.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
-
|
1
|
+
##
|
2
|
+
# @file transformers.rb
|
3
|
+
# Argument Transforms for Brine.
|
2
4
|
#
|
3
5
|
# The Transforms that convert provided inputs to support richer
|
4
6
|
# functionaliy than the simple strings which Cucumber provides.
|
5
7
|
|
6
|
-
|
8
|
+
##
|
9
|
+
# @defgroup Scalar transforms
|
7
10
|
# Convert inputs into basic Ruby data types which represent a single value
|
11
|
+
##
|
8
12
|
|
9
13
|
# Integers
|
10
14
|
Transform /\A(-?\d+)\z/ do |number|
|
@@ -31,8 +35,10 @@ Transform /^#{DATE}T#{TIME}#{MILLIS}#{TZ}$/ do |date|
|
|
31
35
|
Time.parse(date)
|
32
36
|
end
|
33
37
|
|
34
|
-
|
38
|
+
##
|
39
|
+
# @defgroup Structure transforms
|
35
40
|
# Converts inputs to general data structures
|
41
|
+
##
|
36
42
|
|
37
43
|
# Lists
|
38
44
|
Transform /\A\[.*\]\z/m do |input|
|
@@ -46,8 +52,10 @@ Transform /\A{.*}\z$/m do |input|
|
|
46
52
|
JSON.parse(input)
|
47
53
|
end
|
48
54
|
|
49
|
-
|
55
|
+
##
|
56
|
+
# @defgroup Atypical transforms
|
50
57
|
# Transforms for which data type is not the primary focus
|
58
|
+
##
|
51
59
|
|
52
60
|
# Whitespace removal transforms
|
53
61
|
# Handle stripping leading and trailing whitespace.
|