brine-dsl 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/Gemfile.lock +38 -19
- data/brine-dsl.gemspec +8 -8
- data/lib/brine.rb +12 -25
- data/lib/brine/assertions.rb +123 -0
- data/lib/brine/cleaning_up.rb +28 -18
- data/lib/brine/client_building.rb +22 -22
- data/lib/brine/coercing.rb +15 -15
- data/lib/brine/hooks.rb +1 -1
- data/lib/brine/mustache_expanding.rb +54 -23
- data/lib/brine/performing.rb +51 -25
- data/lib/brine/requesting.rb +97 -26
- data/lib/brine/selecting.rb +239 -35
- data/lib/brine/test_steps.rb +16 -19
- data/lib/brine/transforming.rb +30 -24
- data/lib/brine/type_checking.rb +25 -14
- metadata +7 -14
- data/lib/brine/rest_steps.rb +0 -119
- data/lib/brine/step_definitions/assertions.rb +0 -50
- data/lib/brine/step_definitions/assignment.rb +0 -42
- data/lib/brine/step_definitions/cleanup.rb +0 -4
- data/lib/brine/step_definitions/perform.rb +0 -16
- data/lib/brine/step_definitions/request_construction.rb +0 -28
- data/lib/brine/step_definitions/selection.rb +0 -49
- data/lib/brine/util.rb +0 -46
data/lib/brine/selecting.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
##
|
2
2
|
# @file selecting.rb
|
3
|
-
#
|
3
|
+
# Support selection of one or more values to be used by Brine (normally for assertion).
|
4
4
|
##
|
5
|
-
|
6
5
|
require 'brine/transforming.rb'
|
7
6
|
|
8
7
|
module Brine
|
9
8
|
|
10
9
|
##
|
11
|
-
#
|
10
|
+
# Provide assorted means to select particular values out of objects/graphs.
|
12
11
|
##
|
13
12
|
module Selecting
|
14
13
|
|
@@ -17,7 +16,7 @@ module Brine
|
|
17
16
|
require 'jsonpath'
|
18
17
|
|
19
18
|
##
|
20
|
-
#
|
19
|
+
# Allow selection of one or more values.
|
21
20
|
# This Selector will test whether the targeted value itself satisfies the assertion.
|
22
21
|
#
|
23
22
|
# RSpec is used within this implementation to perform assertions.
|
@@ -29,15 +28,15 @@ module Brine
|
|
29
28
|
include RSpec::Matchers
|
30
29
|
|
31
30
|
##
|
32
|
-
# [Coercer]
|
31
|
+
# [Coercer] Expose the Coercer that may modify values prior to performing assertions.
|
33
32
|
##
|
34
33
|
attr_accessor :coercer
|
35
34
|
|
36
35
|
##
|
37
36
|
# Construct a selector to perform assertions against a provided target.
|
38
37
|
#
|
39
|
-
# @param [Object]
|
40
|
-
# @param [Boolean]
|
38
|
+
# @param target [Object] Provide the value against which assertions will be performed.
|
39
|
+
# @param negated [Boolean] Specify whether the assertions from this selector should be negated.
|
41
40
|
# This is deprecated and should instead be passed to #assert_that.
|
42
41
|
##
|
43
42
|
def initialize(target, negated=false)
|
@@ -49,10 +48,11 @@ module Brine
|
|
49
48
|
# Optionally perform some modification to the RSpec matcher prior to assertion.
|
50
49
|
#
|
51
50
|
# This is designed to allow subclassess to be able to modify the way
|
52
|
-
# in which matchers are applied against the values.
|
51
|
+
# in which matchers are applied against the values.
|
52
|
+
# The default implementation is a passthrough.
|
53
53
|
#
|
54
|
-
# @param [RSpec::Matcher]
|
55
|
-
# @return [RSpec::Matcher]
|
54
|
+
# @param matcher [RSpec::Matcher] Relay the matcher originally passed to #assert_that.
|
55
|
+
# @return [RSpec::Matcher] Return the Matcher to use while performing the assertion.
|
56
56
|
##
|
57
57
|
def filter_matcher(matcher)
|
58
58
|
matcher
|
@@ -63,16 +63,17 @@ module Brine
|
|
63
63
|
#
|
64
64
|
# The values will be coerced prior to evaluation.
|
65
65
|
#
|
66
|
-
# @param [Object]
|
66
|
+
# @param value [Object] Specify the value/parameter against which the target will be compared.
|
67
67
|
# In cases where no parameter is needed for comparison, this may be nil.
|
68
|
-
# @param [
|
69
|
-
# @param [
|
68
|
+
# @param binding [Object] Provide the binding environment which will be used to expand any templates
|
69
|
+
# @param negated [Boolean] Specify whether the assertion should be expected to _fail_, if false it should pass.
|
70
|
+
# @param [Block] Define the logic which will be passed a coerced copy of `value` and which should return an
|
70
71
|
# RSpec matcher which will be evaluated against the coerced target value.
|
71
72
|
##
|
72
|
-
def assert_that(value, negated=nil)
|
73
|
+
def assert_that(value, binding, negated=nil)
|
73
74
|
# shim while moving negation to assertions.
|
74
75
|
negated = @negated if negated.nil?
|
75
|
-
target, value = coercer.coerce(expand(@target), expand(value))
|
76
|
+
target, value = coercer.coerce(expand(@target, binding), expand(value, binding))
|
76
77
|
message = negated ? :to_not : :to
|
77
78
|
matcher = filter_matcher(yield(value))
|
78
79
|
expect(target).send(message, matcher)
|
@@ -81,7 +82,7 @@ module Brine
|
|
81
82
|
end
|
82
83
|
|
83
84
|
##
|
84
|
-
#
|
85
|
+
# Define a Selector which will test whether any of the children of the targeted value satisfy the assertion.
|
85
86
|
##
|
86
87
|
class AnySelector < Selector
|
87
88
|
def filter_matcher(matcher)
|
@@ -90,7 +91,7 @@ module Brine
|
|
90
91
|
end
|
91
92
|
|
92
93
|
##
|
93
|
-
#
|
94
|
+
# Define a Selector which will test whether all of the children of the targeted value satisfy the assertion.
|
94
95
|
##
|
95
96
|
class AllSelector < Selector
|
96
97
|
def filter_matcher(matcher)
|
@@ -101,8 +102,8 @@ module Brine
|
|
101
102
|
##
|
102
103
|
# Activate a Selector for the provided target.
|
103
104
|
#
|
104
|
-
# @param [Object]
|
105
|
-
# @param [Boolean]
|
105
|
+
# @param target [Object] Provide the value which the Selector should target.
|
106
|
+
# @param negated [Boolean] Specify whether the assertions should be expected to fail (DEPRECATED).
|
106
107
|
##
|
107
108
|
def select(target, negated=nil)
|
108
109
|
use_selector(Selector.new(target, negated))
|
@@ -111,8 +112,8 @@ module Brine
|
|
111
112
|
##
|
112
113
|
# Activate a Selector for any of the children of the provided target.
|
113
114
|
#
|
114
|
-
# @param [Object]
|
115
|
-
# @param [Boolean]
|
115
|
+
# @param target [Object] Provide the value which the Selector should target.
|
116
|
+
# @param negated [Boolean] Specify whether the assertions should be expected to fail (DEPRECATED).
|
116
117
|
##
|
117
118
|
def select_any(target, negated=nil)
|
118
119
|
use_selector(AnySelector.new(target, negated))
|
@@ -121,8 +122,8 @@ module Brine
|
|
121
122
|
##
|
122
123
|
# Activate a Selector for all of the children of the provided target.
|
123
124
|
#
|
124
|
-
# @param [Object]
|
125
|
-
# @param [Boolean]
|
125
|
+
# @param target [Object] Provide the value which the Selector should target.
|
126
|
+
# @param negated [Boolean] Specify whether the assertions should be expected to fail (DEPRECATED).
|
126
127
|
##
|
127
128
|
def select_all(target, negated=nil)
|
128
129
|
use_selector(AllSelector.new(target, negated))
|
@@ -131,7 +132,7 @@ module Brine
|
|
131
132
|
##
|
132
133
|
# Configure selector and make it the active Selector.
|
133
134
|
#
|
134
|
-
# @param [Selector]
|
135
|
+
# @param selector [Selector] Provide the selector which will be activated.
|
135
136
|
##
|
136
137
|
def use_selector(selector)
|
137
138
|
selector.coercer = coercer
|
@@ -139,32 +140,235 @@ module Brine
|
|
139
140
|
end
|
140
141
|
|
141
142
|
##
|
142
|
-
#
|
143
|
+
# Return the currently active Selector.
|
143
144
|
#
|
144
|
-
# @return
|
145
|
+
# @return [Selector] Return the Selector as set by #use_selector.
|
145
146
|
##
|
146
147
|
def selector
|
147
148
|
@selector
|
148
149
|
end
|
149
150
|
|
151
|
+
##
|
152
|
+
# Capture a path for which the value will be retrieved from a root.
|
153
|
+
##
|
154
|
+
class Traversal
|
155
|
+
|
156
|
+
##
|
157
|
+
# Return a traversal for the provided path.
|
158
|
+
#
|
159
|
+
# @param path [String] Define the JSONPath for the location of the value(s) to retrieve.
|
160
|
+
# @param is_plural [Boolean] Specify whether a collection should be returned for possibly multiple values,
|
161
|
+
# false if only a single value should be expected/returned.
|
162
|
+
##
|
163
|
+
def initialize(path, is_plural)
|
164
|
+
@path = path
|
165
|
+
@message = is_plural ? :on : :first
|
166
|
+
end
|
167
|
+
|
168
|
+
##
|
169
|
+
# Return values out of the provided root based on the traversal definition.
|
170
|
+
#
|
171
|
+
# @param root [String] Provide the JSON structure from which the value will be retrieved.
|
172
|
+
# @return [Object] Return the value or values (if is_plural) at the defined path or nil if none found.
|
173
|
+
##
|
174
|
+
def visit(root)
|
175
|
+
!@path ? root : JsonPath.new("$.#{@path}").send(@message, root)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
##
|
180
|
+
# Return a Traversal based on the provided arguments.
|
181
|
+
#
|
182
|
+
# This primarily exists as the exported interface to retrieve a Traversal instance.
|
183
|
+
#
|
184
|
+
# @param path [String] Define the JSONPath to which the traversal should descend.
|
185
|
+
# @param is_plural [Object] Specify whether to produce a traversal for a collection of all matches:
|
186
|
+
# nil will target only a single match, any non-nil value will target all matches.
|
187
|
+
# @return [Traversal] Return a Traversal configured based on the provided arguments.
|
188
|
+
##
|
189
|
+
def traversal(path, is_plural)
|
190
|
+
Traversal.new(path, !is_plural.nil?)
|
191
|
+
end
|
150
192
|
end
|
151
193
|
|
152
194
|
# Mix the Selecting module functionality into the main Brine module.
|
153
195
|
include Selecting
|
196
|
+
|
154
197
|
end
|
155
198
|
|
199
|
+
##
|
200
|
+
# Retrieve the requested attribute from the current response.
|
156
201
|
#
|
157
|
-
#
|
202
|
+
# @param attribute [String] Specify the attribute to return from the response.
|
203
|
+
# @return [Object] Return the value of the attribute for the current response.
|
204
|
+
##
|
205
|
+
def response_attribute(attribute)
|
206
|
+
response.send(attribute.to_sym)
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
##
|
211
|
+
# Extract assertion step text.
|
212
|
+
##
|
213
|
+
ParameterType(
|
214
|
+
name: 'assertion',
|
215
|
+
regexp: /.*[^:]/,
|
216
|
+
transformer: -> (input) { input }
|
217
|
+
)
|
218
|
+
|
219
|
+
##
|
220
|
+
# Extract the text for a standard HTTP method.
|
221
|
+
##
|
222
|
+
ParameterType(
|
223
|
+
name: 'http_method',
|
224
|
+
regexp: /(DELETE|GET|HEAD|OPTIONS|PATCH|POST|PUT)/,
|
225
|
+
transformer: -> (input) { input }
|
226
|
+
)
|
227
|
+
|
228
|
+
##
|
229
|
+
# Indicate whether not is present.
|
230
|
+
##
|
231
|
+
ParameterType(
|
232
|
+
name: 'maybe_not',
|
233
|
+
regexp: /( not)?/,
|
234
|
+
transformer: -> (input=nil) { !input.nil? }
|
235
|
+
)
|
236
|
+
|
237
|
+
##
|
238
|
+
# Extract the text for a supported response attribute.
|
239
|
+
##
|
240
|
+
ParameterType(
|
241
|
+
name: 'response_attribute',
|
242
|
+
regexp: /(status|headers|body)/,
|
243
|
+
transformer: -> (input) { input }
|
244
|
+
)
|
245
|
+
|
246
|
+
# Messing with the parameters is due to cucumber expressions
|
247
|
+
# not working properly...that should be chased down.
|
248
|
+
|
249
|
+
##
|
250
|
+
# Produce a Traversal for one or all elements at the specified path.
|
251
|
+
##
|
252
|
+
ParameterType(
|
253
|
+
name: 'traversal',
|
254
|
+
regexp: /(?: child(ren)? `([^`]*)`)?/,
|
255
|
+
transformer: -> (plural_or_path=nil, path=nil) {
|
256
|
+
if path.nil?
|
257
|
+
path=plural_or_path
|
258
|
+
plural_or_path=nil
|
259
|
+
end
|
260
|
+
traversal(path, plural_or_path)
|
261
|
+
}
|
262
|
+
)
|
263
|
+
|
264
|
+
##
|
265
|
+
# Select a directly provided value.
|
158
266
|
#
|
159
|
-
|
160
|
-
|
161
|
-
|
267
|
+
# @param value [Object] Provide the value for which the assertion will be evaluated.
|
268
|
+
# @param negated [Object] Indicate whether the assertion should be exected to fail.
|
269
|
+
# @param assertion [String] Provide the assertion step to evaluate.
|
270
|
+
##
|
271
|
+
Then('the value of {grave_param} is{maybe_not} {assertion}') do |value, negated, assertion|
|
272
|
+
select(value, negated)
|
162
273
|
# Stringify in case the assertion clause is a template.
|
163
|
-
step "it is #{assertion
|
274
|
+
step "it is #{assertion}"
|
275
|
+
end
|
276
|
+
|
277
|
+
##
|
278
|
+
# Evaluate an assertion against a response attribute.
|
279
|
+
#
|
280
|
+
# @param attribute [String] Indicate from which response attribute the value will be selected.
|
281
|
+
# @param traversal [Traversal] Provide a Traversal to retrieve the value from the attribute.
|
282
|
+
# @param negated [Boolean] Specify whether the assertion should be expected to fail (DEPRECATED).
|
283
|
+
# @param assertion [Object] Provide the assertion step to evaluate.
|
284
|
+
##
|
285
|
+
Then('the value of the response {response_attribute}{traversal} is{maybe_not} {assertion}') do
|
286
|
+
|attribute, traversal, negated, assertion|
|
287
|
+
perform do
|
288
|
+
select(traversal.visit(response_attribute(attribute)), negated)
|
289
|
+
step "it is #{assertion}"
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
##
|
295
|
+
# Evaluate an assertion against a response attribute and provide a docstring parameter.
|
296
|
+
#
|
297
|
+
# @param attribute [String] Indicate from which response attribute the value will be selected.
|
298
|
+
# @param traversal [Traversal] Provide a Traversal to retrieve the value from the attribute.
|
299
|
+
# @param negated [Boolean] Specify whether the assertion should be expected to fail (DEPRECATED).
|
300
|
+
# @param assertion [Object] Provide the assertion step to evaluate.
|
301
|
+
# @param multi [String] Pass a docstring parameter which will be forwarded to the assertion.
|
302
|
+
##
|
303
|
+
Then('the value of the response {response_attribute}{traversal} is{maybe_not} {assertion}:') do
|
304
|
+
|attribute, traversal, negated, assertion, multi|
|
305
|
+
perform do
|
306
|
+
select(traversal.visit(response_attribute(attribute)), negated)
|
307
|
+
step "it is #{assertion}:", multi
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
##
|
312
|
+
# Evaluate an assertion against at least one matched value from the response attribute.
|
313
|
+
#
|
314
|
+
# @param attribute [String] Indicate from which response attribute the values will be selected.
|
315
|
+
# @param traversal [Traversal] Provide a Traversal to retrieve values from the attribute.
|
316
|
+
# @param negated [Boolean] Specify whether the assertion should be expected to fail (DEPRECATED).
|
317
|
+
# @param assertion [Object] Provide the assertion step to evaluate.
|
318
|
+
##
|
319
|
+
Then('the value of the response {response_attribute}{traversal} does{maybe_not} have any element that is {assertion}') do
|
320
|
+
|attribute, traversal, negated, assertion|
|
321
|
+
perform do
|
322
|
+
select_any(traversal.visit(response_attribute(attribute)), negated)
|
323
|
+
step "it is #{assertion}"
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
##
|
328
|
+
# Evaluate an assertion against at least one matched value from the response attribute and provide a docstring parameter.
|
329
|
+
#
|
330
|
+
# @param attribute [String] Indicate from which response attribute the values will be selected.
|
331
|
+
# @param traversal [Traversal] Provide a Traversal to retrieve values from the attribute.
|
332
|
+
# @param negated [Boolean] Specify whether the assertion should be expected to fail (DEPRECATED).
|
333
|
+
# @param assertion [Object] Provide the assertion step to evaluate.
|
334
|
+
# @param multi [String] Pass a docstring parameter which will be forwarded to the assertion.
|
335
|
+
##
|
336
|
+
Then('the value of the response {response_attribute}{traversal} does{maybe_not} have any element that is {assertion}:') do
|
337
|
+
|attribute, traversal, negated, assertion, multi|
|
338
|
+
perform do
|
339
|
+
select_any(traversal.visit(response_attribute(attribute)), negated)
|
340
|
+
step "it is #{assertion}", multi
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
##
|
345
|
+
# Evaluate an assertion against ALL matched value from the response attribute.
|
346
|
+
#
|
347
|
+
# @param attribute [String] Indicate from which response attribute the values will be selected.
|
348
|
+
# @param traversal [Traversal] Provide a Traversal to retrieve values from the attribute.
|
349
|
+
# @param assertion [Object] Provide the assertion step to evaluate.
|
350
|
+
##
|
351
|
+
Then('the value of the response {response_attribute}{traversal} has elements which are all {assertion}') do
|
352
|
+
|attribute, traversal, assertion|
|
353
|
+
perform do
|
354
|
+
select_all(traversal.visit(response_attribute(attribute)), false)
|
355
|
+
step "it is #{assertion}"
|
356
|
+
end
|
164
357
|
end
|
165
358
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
359
|
+
##
|
360
|
+
# Evaluate an assertion against ALL matched value from the response attribute and provide a docstring argument.
|
361
|
+
#
|
362
|
+
# @param attribute [String] Indicate from which response attribute the values will be selected.
|
363
|
+
# @param traversal [Traversal] Provide a Traversal to retrieve values from the attribute.
|
364
|
+
# @param assertion [Object] Provide the assertion step to evaluate.
|
365
|
+
# @param multi [String] Pass a docstring parameter which will be forwarded to the assertion.
|
366
|
+
##
|
367
|
+
Then('the value of the response {response_attribute}{traversal} has elements which are all {assertion}:') do
|
368
|
+
|attribute, traversal, assertion, multi|
|
369
|
+
perform do
|
370
|
+
select_all(traversal.visit(response_attribute(attribute)), false)
|
371
|
+
step "it is #{assertion}", multi.to_json
|
372
|
+
end
|
170
373
|
end
|
374
|
+
|
data/lib/brine/test_steps.rb
CHANGED
@@ -3,7 +3,8 @@ require 'rspec'
|
|
3
3
|
# Steps used to test this library
|
4
4
|
# Not loaded by default (except in the tests)
|
5
5
|
#
|
6
|
-
|
6
|
+
|
7
|
+
require 'brine/selecting'
|
7
8
|
|
8
9
|
ENV['BRINE_DURATION_SECONDS_short'] = '3'
|
9
10
|
ENV['BRINE_DURATION_SECONDS_long'] = '6'
|
@@ -105,60 +106,56 @@ Before do
|
|
105
106
|
end
|
106
107
|
end
|
107
108
|
|
108
|
-
Given(
|
109
|
+
Given('expected response status of {grave_param}') do |status|
|
109
110
|
stub.response.status = status
|
110
111
|
end
|
111
112
|
|
112
|
-
Given(
|
113
|
+
Given('expected response status sequence of {grave_param}') do |seq|
|
113
114
|
@stub = ResponseStatusSequenceStubBuilder.new(stub, seq)
|
114
115
|
end
|
115
116
|
|
116
|
-
Given(
|
117
|
+
Given('expected request body:') do |body|
|
117
118
|
stub.request.body = body
|
118
119
|
end
|
119
120
|
|
120
|
-
Given(
|
121
|
-
stub.request.headers = headers
|
121
|
+
Given('expected request headers:') do |headers|
|
122
|
+
stub.request.headers = transformed_parameter(headers)
|
122
123
|
end
|
123
124
|
|
124
|
-
Given(
|
125
|
+
Given('expected {http_method} sent to {grave_param}') do |method, path|
|
125
126
|
stub.request.method = method
|
126
127
|
stub.request.path = path
|
127
128
|
build_stub
|
128
129
|
end
|
129
130
|
|
130
|
-
When(
|
131
|
+
When('the response body is assigned:') do |input|
|
131
132
|
@response ||= StubResponse.new
|
132
|
-
@response.body = input
|
133
|
+
@response.body = transformed_parameter(input)
|
133
134
|
end
|
134
135
|
|
135
|
-
When(
|
136
|
+
When('the response headers is assigned {grave_param}') do |input|
|
136
137
|
@response ||= StubResponse.new
|
137
138
|
@response.headers = input
|
138
139
|
end
|
139
140
|
|
140
|
-
When(
|
141
|
+
When('the response body is assigned {grave_param}') do |input|
|
141
142
|
@response ||= StubResponse.new
|
142
143
|
@response.body = input
|
143
144
|
end
|
144
145
|
|
145
|
-
When(
|
146
|
-
replaced_with('When', 'the response body is assigned:', '1.0.0', input.to_json)
|
147
|
-
end
|
148
|
-
|
149
|
-
When /^the response status is assigned `([^`]*)`$/ do |status|
|
146
|
+
When('the response status is assigned {grave_param}') do |status|
|
150
147
|
@response ||= StubResponse.new
|
151
148
|
@response.status = status.to_i # this coercion isn't needed but is a guarantee
|
152
149
|
end
|
153
150
|
|
154
|
-
When
|
151
|
+
When('the response is delayed {int} seconds') do |seconds|
|
155
152
|
@response = DelayedStubResponse.new(seconds)
|
156
153
|
end
|
157
154
|
|
158
|
-
Then(
|
155
|
+
Then('the response body as JSON is:') do |text|
|
159
156
|
expect(response.body.to_json).to eq text
|
160
157
|
end
|
161
158
|
|
162
|
-
Then(
|
159
|
+
Then('expected calls are verified') do
|
163
160
|
$stubs.verify_stubbed_calls
|
164
161
|
end
|