endpoint_stub 1.1.0 → 1.4.5
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 +2 -1
- data/lib/endpoint/response.rb +148 -0
- data/lib/endpoint/stub.rb +79 -108
- data/lib/endpoint_stub.rb +17 -6
- data/lib/endpoint_stub/version.rb +1 -1
- data/spec/endpoint/stub_spec.rb +122 -4
- data/spec/spec_helper.rb +7 -0
- metadata +3 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d478a91265f34ca548261653054f9c7f80dfd5b5
|
4
|
+
data.tar.gz: a7302ecb8415182aee62cb945c44118a5fe25463
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f67ed8b7eae33b91bb8264c9cef4ca8dd3e061bbf3668c02d7f931003e8ac36ae68e706e7ee5795af6346c50dd438d71666138ae4d02852293abe56a32d53fab
|
7
|
+
data.tar.gz: ef2b62184775a3d52f0efda1db83df8b17f37b3237ac54a1ab133c4092778c0a7c6c284208bda6910b1a2dde663ecaeb30f212e1a3e4c2b5955df909f38cf9cd
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ outdated, so I decided to make my own using WebMock.
|
|
6
6
|
EndpointStub is kind of like the built in ActiveResource HTTPMock, except
|
7
7
|
you can bind logic and dynamic routes to it, so it's like a mini controller
|
8
8
|
almost. EndpointStub comes with the default RESTful CRUD actions supported
|
9
|
-
by ActiveResource
|
9
|
+
by ActiveResource built in (currently JSON format only). It also comes with
|
10
10
|
an interface for defining your own routes and logic.
|
11
11
|
|
12
12
|
Nested resources are currently pending, but definitely implementable via custom
|
@@ -16,6 +16,7 @@ response mocking.
|
|
16
16
|
|
17
17
|
Add this line to your application's Gemfile:
|
18
18
|
|
19
|
+
gem 'webmock'
|
19
20
|
gem 'endpoint_stub'
|
20
21
|
|
21
22
|
And then execute:
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'webmock'
|
2
|
+
|
3
|
+
class Response
|
4
|
+
include WebMock::API
|
5
|
+
|
6
|
+
# For remembering where a uri-based parameter is located.
|
7
|
+
ParamIndices = Struct.new(:slash, :dot)
|
8
|
+
# Allows more comfortable use of Symbol keys when accessing
|
9
|
+
# params (which are string keys).
|
10
|
+
class Params < Hash
|
11
|
+
def [](key)
|
12
|
+
super(key.to_s)
|
13
|
+
end
|
14
|
+
def []=(key, value)
|
15
|
+
super(key.to_s, value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(type, url, stub, &proc)
|
20
|
+
@param_indices = {}
|
21
|
+
|
22
|
+
@url_regex = build_url_regex!(url)
|
23
|
+
|
24
|
+
@type = type
|
25
|
+
@stub = stub
|
26
|
+
|
27
|
+
@response_stack = [proc]
|
28
|
+
end
|
29
|
+
|
30
|
+
def activated?
|
31
|
+
!@stubbed_request.nil?
|
32
|
+
end
|
33
|
+
|
34
|
+
# This should add the stubbed request to WebMock.
|
35
|
+
def activate!
|
36
|
+
@stubbed_request = stub_request(@type, @url_regex).
|
37
|
+
to_return(&create_response_proc(@response_stack))
|
38
|
+
end
|
39
|
+
|
40
|
+
# This should remove the request stubbed by #activate!
|
41
|
+
# Passing a block will reactivate when done with block logic
|
42
|
+
# if previously activated.
|
43
|
+
def deactivate!
|
44
|
+
remove_request_stub @stubbed_request
|
45
|
+
if block_given?
|
46
|
+
yield
|
47
|
+
activate! if @stubbed_request
|
48
|
+
else
|
49
|
+
@stubbed_request = nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def reset!
|
54
|
+
deactivate!
|
55
|
+
activate!
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_to_stack(&proc)
|
59
|
+
deactivate! do
|
60
|
+
@response_stack << proc
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Return to the first stubbed response.
|
65
|
+
def drop_overrides!
|
66
|
+
deactivate! do
|
67
|
+
remove_request_stub @stubbed_request
|
68
|
+
@response_stack = @response_stack[0..1]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Creates a proc that can be passed as a block to WebMock's stub_request method.
|
75
|
+
def create_response_proc(callback_stack)
|
76
|
+
execute_callback_with_super = ->(stack, request, params, stub) {
|
77
|
+
# the p_* args represent arguments potentially passed by the user's super call.
|
78
|
+
stack.last.call(request, params, stub) do |p_request, p_params, p_stub|
|
79
|
+
if stack.count == 1
|
80
|
+
{}
|
81
|
+
else
|
82
|
+
execute_callback_with_super.call(stack[0...-1], p_request || request, p_params || params, p_stub || stub)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
}
|
86
|
+
|
87
|
+
# This proc is passed as a block to #to_return when creating the stub.
|
88
|
+
Proc.new do |request|
|
89
|
+
params = extract_params(request)
|
90
|
+
|
91
|
+
results = execute_callback_with_super.call(
|
92
|
+
callback_stack, request, params, @stub)
|
93
|
+
|
94
|
+
results[:body] = results[:body].to_json unless results[:body].is_a? String
|
95
|
+
results
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Bang is there because this method populates @param_indices.
|
100
|
+
def build_url_regex!(url)
|
101
|
+
regex = ""
|
102
|
+
separate(url).each_with_index do |x, slash_index|
|
103
|
+
regex += '/' unless slash_index == 0
|
104
|
+
# If there is a colon, it's a parameter. i.e. /resource/:id.json
|
105
|
+
if x.include? ':' and !(x[1..-1] =~ /^\d$/) # If it's just numbers, it's probably a port number
|
106
|
+
# We split by dot at this point to separate the parameter from any
|
107
|
+
# format/domain related suffix.
|
108
|
+
dot_split = x.split('.')
|
109
|
+
inner_regex = []
|
110
|
+
|
111
|
+
dot_split.each_with_index do |name, dot_index|
|
112
|
+
# A parameter can show up after a dot as well. i.e. /resource/:id.:format
|
113
|
+
inner_regex << if name.include? ':'
|
114
|
+
param_name = name[1..-1]
|
115
|
+
@param_indices[param_name] = ParamIndices.new(slash_index, dot_index)
|
116
|
+
# Add .+ regex to capture any data at this point in the url.
|
117
|
+
".+"
|
118
|
+
else
|
119
|
+
# If there's no colon, it's a static part of the target url.
|
120
|
+
Regexp.escape(name)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# "inner_regex" was built by splitting on dots, so we put the dots back.
|
125
|
+
regex += inner_regex.join('\.')
|
126
|
+
else
|
127
|
+
# No colon, so this segment is static.
|
128
|
+
regex += Regexp.escape(x)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
Regexp.new regex
|
132
|
+
end
|
133
|
+
|
134
|
+
def extract_params(request)
|
135
|
+
url = separate request.uri
|
136
|
+
params = Params.new
|
137
|
+
@param_indices.each do |param_name, index|
|
138
|
+
value = url[index.slash].split('.')[index.dot]
|
139
|
+
|
140
|
+
params[param_name] = value
|
141
|
+
end
|
142
|
+
params
|
143
|
+
end
|
144
|
+
|
145
|
+
def separate(url)
|
146
|
+
url.to_s[url.to_s.index('://')+3..-1].split '/'
|
147
|
+
end
|
148
|
+
end
|
data/lib/endpoint/stub.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'endpoint/response'
|
1
2
|
require 'endpoint_stub'
|
2
3
|
require 'webmock'
|
3
4
|
|
@@ -21,7 +22,7 @@ module Endpoint
|
|
21
22
|
# custom responses if needed.
|
22
23
|
def create_for(model, options={}, &block)
|
23
24
|
model = assure_model model
|
24
|
-
return if stubs.keys.include? model
|
25
|
+
return if stubs.keys.map(&:name).include? model.name
|
25
26
|
new_stub = Stub.new(model, options)
|
26
27
|
|
27
28
|
EndpointStub::Config.default_responses.each do |response|
|
@@ -46,6 +47,10 @@ module Endpoint
|
|
46
47
|
@stubs[assure_model(model)]
|
47
48
|
end
|
48
49
|
|
50
|
+
def clear_all_records!
|
51
|
+
@stubs.values.each(&:clear_records!)
|
52
|
+
end
|
53
|
+
|
49
54
|
##
|
50
55
|
# Clears all endpoint stubs.
|
51
56
|
def clear!
|
@@ -59,6 +64,10 @@ module Endpoint
|
|
59
64
|
create_for model or get_for model
|
60
65
|
end
|
61
66
|
|
67
|
+
def each(&block)
|
68
|
+
@stubs.each(&block)
|
69
|
+
end
|
70
|
+
|
62
71
|
private
|
63
72
|
def assure_model(model)
|
64
73
|
if model.ancestors.include? ActiveResource::Base
|
@@ -71,12 +80,13 @@ module Endpoint
|
|
71
80
|
|
72
81
|
attr_reader :defaults
|
73
82
|
attr_reader :model
|
83
|
+
attr_reader :site
|
74
84
|
attr_accessor :records
|
75
85
|
def initialize(model, options)
|
76
86
|
@defaults = options[:defaults] || {}
|
77
87
|
|
78
88
|
@model = model
|
79
|
-
@site = URI "#{model.site}/#{model.name.underscore.pluralize}"
|
89
|
+
@site = URI "#{model.site}/#{model.name.split('::').last.underscore.pluralize}"
|
80
90
|
|
81
91
|
@responses = {}
|
82
92
|
|
@@ -93,6 +103,7 @@ module Endpoint
|
|
93
103
|
attrs[:id] = current_id
|
94
104
|
attrs.merge!(@defaults) { |k,a,b| a }
|
95
105
|
@records << attrs
|
106
|
+
attrs
|
96
107
|
end
|
97
108
|
|
98
109
|
##
|
@@ -117,6 +128,14 @@ module Endpoint
|
|
117
128
|
end
|
118
129
|
end
|
119
130
|
|
131
|
+
##
|
132
|
+
# Clear all records in this stub.
|
133
|
+
def clear_records!
|
134
|
+
@records = []
|
135
|
+
end
|
136
|
+
|
137
|
+
##
|
138
|
+
# Get the record at the given id. Accepts strings as well as ints.
|
120
139
|
def record(id)
|
121
140
|
@records[id.to_i]
|
122
141
|
end
|
@@ -171,25 +190,53 @@ module Endpoint
|
|
171
190
|
# interact with the stubbed records.
|
172
191
|
def mock_response(type, route='', proc=nil, &block)
|
173
192
|
proc = block if block_given?
|
193
|
+
route = clean_route route
|
174
194
|
|
195
|
+
@responses[type] ||= {}
|
196
|
+
@responses[type][route].deactivate! if @responses[type][route]
|
197
|
+
@responses[type][route] = Response.new(type, prepare_uri(type, route), self, &proc)
|
198
|
+
@responses[type][route].activate!
|
199
|
+
end
|
200
|
+
|
201
|
+
##
|
202
|
+
# Same thing as mock_response, except it will not overWRITE existing
|
203
|
+
# mocks. Instead, it allows you to call a block inside of your response
|
204
|
+
# which will act as a 'super' call, invoking previously defined
|
205
|
+
# responses. Yielding inside a top-level response will give you
|
206
|
+
# an empty hash, so no nil related issues should arrise (unless of
|
207
|
+
# course the super-response returns nil, which it shouldn't).
|
208
|
+
#
|
209
|
+
# Also note that this does not re-activate a deactivated response.
|
210
|
+
def override_response(type, route, proc=nil, &block)
|
211
|
+
proc = block if block_given?
|
175
212
|
route = clean_route route
|
176
213
|
|
177
|
-
|
178
|
-
|
179
|
-
if route[0] == '.' && !route.include?('/')
|
180
|
-
# This allows passing '.json', etc as the route
|
181
|
-
if path.last
|
182
|
-
path = path[0...-1] + [path.last+route]
|
183
|
-
else
|
184
|
-
site += route
|
185
|
-
end
|
214
|
+
if @responses[type] and @responses[type][route]
|
215
|
+
@responses[type][route].add_to_stack(&proc)
|
186
216
|
else
|
187
|
-
|
217
|
+
mock_response(type, route, proc)
|
188
218
|
end
|
219
|
+
end
|
189
220
|
|
190
|
-
|
191
|
-
|
192
|
-
|
221
|
+
##
|
222
|
+
# Overrides all currently assigned responses. Will not have any effect
|
223
|
+
# on responses mocked after this method is called.
|
224
|
+
def override_all(&block)
|
225
|
+
@responses.each do |type, responses|
|
226
|
+
responses.each do |route, response|
|
227
|
+
response.add_to_stack(&block)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
##
|
233
|
+
# Removes all overrides, reducing each response to their originals.
|
234
|
+
def drop_overrides!
|
235
|
+
@responses.each do |type, responses|
|
236
|
+
responses.each do |route, response|
|
237
|
+
response.drop_overrides!
|
238
|
+
end
|
239
|
+
end
|
193
240
|
end
|
194
241
|
|
195
242
|
##
|
@@ -204,104 +251,28 @@ module Endpoint
|
|
204
251
|
end
|
205
252
|
|
206
253
|
private
|
207
|
-
def
|
208
|
-
|
209
|
-
|
210
|
-
route
|
211
|
-
end
|
212
|
-
|
213
|
-
class Response
|
214
|
-
include WebMock::API
|
215
|
-
|
216
|
-
# For remembering where a uri-based parameter is located.
|
217
|
-
ParamIndices = Struct.new(:slash, :dot)
|
218
|
-
# Allows more comfortable use of Symbol keys when accessing
|
219
|
-
# params (which are string keys).
|
220
|
-
class Params < Hash
|
221
|
-
def [](key)
|
222
|
-
super(key.to_s)
|
223
|
-
end
|
224
|
-
def []=(key, value)
|
225
|
-
super(key.to_s, value)
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
def initialize(type, url, stub, &proc)
|
230
|
-
@param_indices = {}
|
231
|
-
|
232
|
-
@url_regex = build_url_regex!(url)
|
233
|
-
|
234
|
-
@type = type
|
235
|
-
@proc = proc
|
236
|
-
@stub = stub
|
237
|
-
end
|
238
|
-
|
239
|
-
# Should be called only once, internally to perform the actual WebMock stubbing.
|
240
|
-
def activate!
|
241
|
-
@stubbed_request = stub_request(@type, @url_regex).to_return do |request|
|
242
|
-
params = extract_params(request)
|
243
|
-
|
244
|
-
results = @proc.call(request, params, @stub)
|
245
|
-
results[:body] = results[:body].to_json unless results[:body].is_a? String
|
246
|
-
results
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
# This should remove the request stubbed by #activate!
|
251
|
-
def deactivate!
|
252
|
-
remove_request_stub @stubbed_request
|
253
|
-
end
|
254
|
+
def prepare_uri(type, route)
|
255
|
+
site = "#{@site.scheme}://#{@site.host}:#{@site.port}"
|
256
|
+
path = @site.path.split(/\/+/).reject(&:empty?)
|
254
257
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
# If there is a colon, it's a parameter. i.e. /resource/:id.json
|
262
|
-
if x.include? ':' and !(x[1..-1] =~ /^\d$/) # If it's just numbers, it's probably a port number
|
263
|
-
# We split by dot at this point to separate the parameter from any
|
264
|
-
# format/domain related suffix.
|
265
|
-
dot_split = x.split('.')
|
266
|
-
inner_regex = []
|
267
|
-
|
268
|
-
dot_split.each_with_index do |name, dot_index|
|
269
|
-
# A parameter can show up after a dot as well. i.e. /resource/:id.:format
|
270
|
-
inner_regex << if name.include? ':'
|
271
|
-
param_name = name[1..-1]
|
272
|
-
@param_indices[param_name] = ParamIndices.new(slash_index, dot_index)
|
273
|
-
# Add .+ regex to capture any data at this point in the url.
|
274
|
-
".+"
|
275
|
-
else
|
276
|
-
# If there's no colon, it's a static part of the target url.
|
277
|
-
Regexp.escape(name)
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
|
-
# "inner_regex" was built by splitting on dots, so we put the dots back.
|
282
|
-
regex += inner_regex.join('\.')
|
283
|
-
else
|
284
|
-
# No colon, so this segment is static.
|
285
|
-
regex += Regexp.escape(x)
|
286
|
-
end
|
258
|
+
if route[0] == '.' && !route.include?('/')
|
259
|
+
# This allows passing '.json', etc as the route
|
260
|
+
if path.last
|
261
|
+
path = path[0...-1] + [path.last+route]
|
262
|
+
else
|
263
|
+
site += route
|
287
264
|
end
|
288
|
-
|
265
|
+
else
|
266
|
+
path += route.split('/')
|
289
267
|
end
|
290
268
|
|
291
|
-
|
292
|
-
|
293
|
-
params = Params.new
|
294
|
-
@param_indices.each do |param_name, index|
|
295
|
-
value = url[index.slash].split('.')[index.dot]
|
296
|
-
|
297
|
-
params[param_name] = value
|
298
|
-
end
|
299
|
-
params
|
300
|
-
end
|
269
|
+
URI.parse site+'/'+path.join('/')
|
270
|
+
end
|
301
271
|
|
302
|
-
|
303
|
-
|
304
|
-
|
272
|
+
def clean_route(route)
|
273
|
+
route = route[1..-1] if route[0] == '/'
|
274
|
+
route = route[0...-1] if route[-1] == '/'
|
275
|
+
route
|
305
276
|
end
|
306
277
|
end
|
307
278
|
end
|
data/lib/endpoint_stub.rb
CHANGED
@@ -15,14 +15,12 @@ module EndpointStub
|
|
15
15
|
# as per WebMock, unless relating to an ActiveResource
|
16
16
|
# model.
|
17
17
|
def self.activate!
|
18
|
-
return if Config.activated
|
19
18
|
WebMock.enable!
|
20
19
|
Config.activated = true
|
21
20
|
end
|
22
21
|
# Disable endpoint stubbing.
|
23
22
|
# This allows real HTTP requests again.
|
24
23
|
def self.deactivate!
|
25
|
-
return unless Config.activated
|
26
24
|
WebMock.disable!
|
27
25
|
Config.activated = false
|
28
26
|
end
|
@@ -34,12 +32,25 @@ module EndpointStub
|
|
34
32
|
activate!
|
35
33
|
end
|
36
34
|
|
35
|
+
# Default to being deactivated.
|
36
|
+
deactivate!
|
37
|
+
|
37
38
|
# Feel free to add to these, and they will be applied to every
|
38
39
|
# stubbed endpoint thereafter.
|
39
40
|
Config.default_responses = [
|
40
41
|
### Index ###
|
41
42
|
[:get, '.json', ->(request, params, stub) {
|
42
|
-
|
43
|
+
query = request.uri.query_values
|
44
|
+
|
45
|
+
if !query || query.empty?
|
46
|
+
{ body: stub.records }
|
47
|
+
else
|
48
|
+
{
|
49
|
+
body: stub.records.select do |record|
|
50
|
+
query.all? { |field, value| record[field] == value }
|
51
|
+
end
|
52
|
+
}
|
53
|
+
end
|
43
54
|
}],
|
44
55
|
|
45
56
|
### Show ###
|
@@ -49,8 +60,8 @@ module EndpointStub
|
|
49
60
|
|
50
61
|
### Create ###
|
51
62
|
[:post, '.json', ->(request, params, stub) {
|
52
|
-
stub.add_record(JSON.parse(request.body))
|
53
|
-
{ body:
|
63
|
+
record = stub.add_record(JSON.parse(request.body))
|
64
|
+
{ body: record,
|
54
65
|
status: 201,
|
55
66
|
headers: { 'Location' => stub.location(stub.last_id) }
|
56
67
|
}
|
@@ -59,7 +70,7 @@ module EndpointStub
|
|
59
70
|
### Update ###
|
60
71
|
[:put, '/:id.json', ->(request, params, stub) {
|
61
72
|
if stub.update_record(params[:id], JSON.parse(request.body))
|
62
|
-
{ body:
|
73
|
+
{ body: stub.records[params[:id].to_i], status: 204}
|
63
74
|
else
|
64
75
|
{ body: "Failed to find #{stub.model_name} with id #{params[:id]}",
|
65
76
|
status: 404 }
|
data/spec/endpoint/stub_spec.rb
CHANGED
@@ -2,6 +2,17 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
class TestModel < ActiveResource::Base
|
4
4
|
self.site = "http://www.not-a-site.com/api"
|
5
|
+
alias_method :to_param, :id
|
6
|
+
end
|
7
|
+
|
8
|
+
module TestModule
|
9
|
+
class InnerModel < ActiveResource::Base
|
10
|
+
self.site = "http://www.inner-test.com/api"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class TestModelWithPort < ActiveResource::Base
|
15
|
+
self.site = "http://not-a-site.com:777/api"
|
5
16
|
end
|
6
17
|
|
7
18
|
describe Endpoint::Stub, stub_spec: true do
|
@@ -29,6 +40,17 @@ describe Endpoint::Stub, stub_spec: true do
|
|
29
40
|
Endpoint::Stub.create_for(TestModel, {defaults: { test_attr: 'hey' }})
|
30
41
|
expect(Endpoint::Stub[TestModel].defaults.keys).to include :test_attr
|
31
42
|
end
|
43
|
+
|
44
|
+
it 'assigns the url properly for namespaced models' do
|
45
|
+
subject = Endpoint::Stub.create_for TestModule::InnerModel
|
46
|
+
expect(subject.site.to_s).to_not include "test_module"
|
47
|
+
expect(subject.site.to_s).to include "inner_models"
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should work with a port number other than 80' do
|
51
|
+
Endpoint::Stub.create_for TestModelWithPort
|
52
|
+
expect{TestModelWithPort.create(test_attr: '...')}.to_not raise_error
|
53
|
+
end
|
32
54
|
end
|
33
55
|
|
34
56
|
describe '.clear_for' do
|
@@ -39,7 +61,6 @@ describe Endpoint::Stub, stub_spec: true do
|
|
39
61
|
end
|
40
62
|
end
|
41
63
|
|
42
|
-
|
43
64
|
context 'With a stubbed model' do
|
44
65
|
let!(:test_model_stub) { Endpoint::Stub.create_for(TestModel) }
|
45
66
|
after(:each) do
|
@@ -75,6 +96,16 @@ describe Endpoint::Stub, stub_spec: true do
|
|
75
96
|
subject.save
|
76
97
|
expect(subject.test_attr).to eq "heyyyyyyy"
|
77
98
|
end
|
99
|
+
|
100
|
+
it 'numbers should be converted to numbers' do
|
101
|
+
subject = TestModel.new
|
102
|
+
subject.test_attr = 'hello'
|
103
|
+
subject.test_num = 2.2
|
104
|
+
subject.save
|
105
|
+
subject = TestModel.find(subject.id)
|
106
|
+
expect(subject.test_num).to_not be_a String
|
107
|
+
expect(subject.test_num).to eq 2.2
|
108
|
+
end
|
78
109
|
end
|
79
110
|
|
80
111
|
describe 'creating a new record' do
|
@@ -87,9 +118,47 @@ describe Endpoint::Stub, stub_spec: true do
|
|
87
118
|
|
88
119
|
it 'should work with .create method' do
|
89
120
|
subject = TestModel.create(test_attr: 'wow')
|
90
|
-
expect(subject.id).to eq
|
121
|
+
expect(subject.id).to eq 0
|
91
122
|
expect(subject.test_attr).to eq 'wow'
|
92
123
|
end
|
124
|
+
|
125
|
+
it 'ids should be properly converted to numbers' do
|
126
|
+
TestModel.create(test_attr: 'nice')
|
127
|
+
expect(TestModel.find(0).id).to_not be_a String
|
128
|
+
expect(TestModel.find(0).id).to eq 0
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should allow the record to be saved afterwards' do
|
132
|
+
subject = TestModel.create(test_attr: 'nice')
|
133
|
+
expect(test_model_stub.records.count).to eq 1
|
134
|
+
subject.test_attr = 'nice'
|
135
|
+
subject.save
|
136
|
+
subject.reload
|
137
|
+
expect(subject.test_attr).to eq 'nice'
|
138
|
+
expect(test_model_stub.records.count).to eq 1
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should allow comprehensive editing' do
|
142
|
+
2.times { |n| TestModel.create(test_attr: "cool#{n}") }
|
143
|
+
expect(test_model_stub.records.count).to eq 2
|
144
|
+
|
145
|
+
first = TestModel.first
|
146
|
+
expect(first.test_attr).to eq 'cool0'
|
147
|
+
|
148
|
+
first.test_attr = 'now this'
|
149
|
+
expect(first.save).to be_truthy
|
150
|
+
expect{first.reload}.to_not raise_error
|
151
|
+
expect(first.test_attr).to eq 'now this'
|
152
|
+
|
153
|
+
expect(TestModel.all.count).to eq 2
|
154
|
+
|
155
|
+
TestModel.all.map(&:test_attr).tap do |it|
|
156
|
+
expect(it).to include 'now this'
|
157
|
+
expect(it).to_not include 'cool0'
|
158
|
+
end
|
159
|
+
|
160
|
+
expect(TestModel.all.map(&:id).uniq).to eq TestModel.all.map(&:id)
|
161
|
+
end
|
93
162
|
end
|
94
163
|
|
95
164
|
describe 'destroying a record' do
|
@@ -117,8 +186,8 @@ describe Endpoint::Stub, stub_spec: true do
|
|
117
186
|
end
|
118
187
|
end
|
119
188
|
|
120
|
-
describe 'custom
|
121
|
-
it 'should be addable to existing
|
189
|
+
describe 'custom responses' do
|
190
|
+
it 'should be addable to existing mocks' do
|
122
191
|
test_model_stub.records << { id: 0, test_attr: 'hey' }
|
123
192
|
|
124
193
|
test_model_stub.mock_response(:put, '/:id/change') do |response, params, stub|
|
@@ -141,6 +210,55 @@ describe Endpoint::Stub, stub_spec: true do
|
|
141
210
|
test_model_stub.unmock_response(:put, '/test')
|
142
211
|
expect{TestModel.put(:test)}.to raise_error
|
143
212
|
end
|
213
|
+
|
214
|
+
it 'should be able to overwrite existing mocks with no path' do
|
215
|
+
test_model_stub.records << { id: 0, test_attr: 'hey' }
|
216
|
+
|
217
|
+
test_model_stub.mock_response :get, '.json' do |response, params, stub|
|
218
|
+
{ body: [{ id: 0, test_attr: 'overridden!' }] }
|
219
|
+
end
|
220
|
+
|
221
|
+
expect(TestModel.all.first.test_attr).to eq 'overridden!'
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'should be able to override existing mocks and access the previous implementation' do
|
225
|
+
test_model_stub.records << { id: 0, test_attr: 'hey' }
|
226
|
+
|
227
|
+
test_model_stub.override_response :get, '.json' do |response, params, stub, &sup|
|
228
|
+
body = sup.call[:body]
|
229
|
+
body << { id: 1, test_attr: 'injected!' }
|
230
|
+
{ body: body }
|
231
|
+
end
|
232
|
+
|
233
|
+
expect(TestModel.all.first.test_attr).to eq 'hey'
|
234
|
+
expect(TestModel.all.last.test_attr).to eq 'injected!'
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'should be able to change the parameters for the previous implementation when overriding' do
|
238
|
+
test_model_stub.records += [{ id: 0, test_attr: 'hey'}, {id: 1, test_attr: 'second' }]
|
239
|
+
|
240
|
+
test_model_stub.override_response :get, '/:id.json' do |response, params, stub, &supre|
|
241
|
+
params[:id] = params[:id].to_i + 1
|
242
|
+
supre.call response, params
|
243
|
+
end
|
244
|
+
|
245
|
+
expect(TestModel.find(0).test_attr).to eq 'second'
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'should be able to override all existing mocks' do
|
249
|
+
test_model_stub.records << { id: 0, test_attr: 'hey' }
|
250
|
+
dummy = Class.new do
|
251
|
+
def test; 'here we go'; end
|
252
|
+
end.new
|
253
|
+
expect(dummy).to receive(:test).twice
|
254
|
+
|
255
|
+
test_model_stub.override_all do |response, params, stub, &supre|
|
256
|
+
{ body: dummy.test }
|
257
|
+
end
|
258
|
+
|
259
|
+
TestModel.all
|
260
|
+
TestModel.find(0) rescue ArgumentError
|
261
|
+
end
|
144
262
|
end
|
145
263
|
end
|
146
264
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,8 +2,15 @@ require 'endpoint_stub'
|
|
2
2
|
require 'endpoint/stub'
|
3
3
|
require 'net/http'
|
4
4
|
require 'active_resource'
|
5
|
+
$VERBOSE = nil
|
5
6
|
|
6
7
|
RSpec.configure do |config|
|
8
|
+
EndpointStub.activate!
|
9
|
+
|
10
|
+
config.after :each do
|
11
|
+
Endpoint::Stub.clear_all_records!
|
12
|
+
end
|
13
|
+
|
7
14
|
# The settings below are suggested to provide a good initial experience
|
8
15
|
# with RSpec, but feel free to customize to your heart's content.
|
9
16
|
=begin
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: endpoint_stub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nigel Baillie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activeresource
|
@@ -77,21 +77,15 @@ extensions: []
|
|
77
77
|
extra_rdoc_files: []
|
78
78
|
files:
|
79
79
|
- ".gitignore"
|
80
|
-
- ".idea/.name"
|
81
|
-
- ".idea/.rakeTasks"
|
82
80
|
- ".idea/dictionaries/devmini.xml"
|
83
|
-
- ".idea/encodings.xml"
|
84
|
-
- ".idea/endpoint_stub.iml"
|
85
|
-
- ".idea/misc.xml"
|
86
|
-
- ".idea/modules.xml"
|
87
81
|
- ".idea/scopes/scope_settings.xml"
|
88
|
-
- ".idea/vcs.xml"
|
89
82
|
- ".rspec"
|
90
83
|
- Gemfile
|
91
84
|
- LICENSE.txt
|
92
85
|
- README.md
|
93
86
|
- Rakefile
|
94
87
|
- endpoint_stub.gemspec
|
88
|
+
- lib/endpoint/response.rb
|
95
89
|
- lib/endpoint/stub.rb
|
96
90
|
- lib/endpoint_stub.rb
|
97
91
|
- lib/endpoint_stub/version.rb
|