flexirest 1.6.7 → 1.6.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +54 -48
- data/README.md +0 -0
- data/docs/validation.md +30 -1
- data/flexirest.gemspec +1 -0
- data/lib/flexirest.rb +5 -0
- data/lib/flexirest/base.rb +3 -217
- data/lib/flexirest/base_without_validation.rb +219 -0
- data/lib/flexirest/version.rb +1 -1
- data/spec/lib/activemodel_validations_spec.rb +44 -0
- data/spec/lib/associations_spec.rb +5 -5
- data/spec/lib/base_spec.rb +3 -505
- data/spec/lib/base_without_validation_spec.rb +517 -0
- metadata +21 -2
@@ -0,0 +1,517 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class EmptyExample < Flexirest::BaseWithoutValidation
|
4
|
+
whiny_missing true
|
5
|
+
end
|
6
|
+
|
7
|
+
class TranslatorExample
|
8
|
+
def self.all(object)
|
9
|
+
ret = {}
|
10
|
+
ret["first_name"] = object["name"]
|
11
|
+
ret
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class AlteringClientExample < Flexirest::BaseWithoutValidation
|
16
|
+
translator TranslatorExample
|
17
|
+
base_url "http://www.example.com"
|
18
|
+
|
19
|
+
get :all, "/all", fake:"{\"name\":\"Billy\"}"
|
20
|
+
get :list, "/list", fake:"{\"name\":\"Billy\", \"country\":\"United Kingdom\"}"
|
21
|
+
get :iterate, "/iterate", fake:"{\"name\":\"Billy\", \"country\":\"United Kingdom\"}"
|
22
|
+
get :find, "/find/:id"
|
23
|
+
end
|
24
|
+
|
25
|
+
class RecordResponseExample < Flexirest::BaseWithoutValidation
|
26
|
+
base_url "http://www.example.com"
|
27
|
+
|
28
|
+
record_response do |url, response|
|
29
|
+
raise Exception.new("#{url}|#{response.body}")
|
30
|
+
end
|
31
|
+
|
32
|
+
get :all, "/all"
|
33
|
+
end
|
34
|
+
|
35
|
+
class NonHostnameBaseUrlExample < Flexirest::BaseWithoutValidation
|
36
|
+
base_url "http://www.example.com/v1/"
|
37
|
+
get :all, "/all"
|
38
|
+
end
|
39
|
+
|
40
|
+
class InstanceMethodExample < Flexirest::BaseWithoutValidation
|
41
|
+
base_url "http://www.example.com/v1/"
|
42
|
+
get :all, "/all"
|
43
|
+
end
|
44
|
+
|
45
|
+
class WhitelistedDateExample < Flexirest::BaseWithoutValidation
|
46
|
+
parse_date :updated_at
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
describe Flexirest::BaseWithoutValidation do
|
51
|
+
it 'should instantiate a new descendant' do
|
52
|
+
expect{EmptyExample.new}.to_not raise_error
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should not instantiate a new base class" do
|
56
|
+
expect{Flexirest::Base.new}.to raise_error(Exception)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should save attributes passed in constructor" do
|
60
|
+
client = EmptyExample.new(test: "Something")
|
61
|
+
expect(client._attributes[:test]).to be_a(String)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should allow attribute reading using missing method names" do
|
65
|
+
client = EmptyExample.new(test: "Something")
|
66
|
+
expect(client.test).to eq("Something")
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should allow attribute reading using [] array notation" do
|
70
|
+
client = EmptyExample.new(test: "Something")
|
71
|
+
expect(client["test"]).to eq("Something")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "allows iteration over attributes using each" do
|
75
|
+
client = AlteringClientExample.iterate
|
76
|
+
expect(client).to be_respond_to(:each)
|
77
|
+
keys = []
|
78
|
+
values = []
|
79
|
+
client.each do |key, value|
|
80
|
+
keys << key ; values << value
|
81
|
+
end
|
82
|
+
expect(keys).to eq(%w{name country}.map(&:to_sym))
|
83
|
+
expect(values).to eq(["Billy", "United Kingdom"])
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should automatically parse ISO 8601 format date and time" do
|
87
|
+
t = Time.now
|
88
|
+
client = EmptyExample.new(test: t.iso8601)
|
89
|
+
expect(client["test"]).to be_an_instance_of(DateTime)
|
90
|
+
expect(client["test"].to_s).to eq(t.to_datetime.to_s)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should automatically parse ISO 8601 format date and time with milliseconds" do
|
94
|
+
t = Time.now
|
95
|
+
client = EmptyExample.new(test: t.iso8601(3))
|
96
|
+
expect(client["test"]).to be_an_instance_of(DateTime)
|
97
|
+
expect(client["test"].to_s).to eq(t.to_datetime.to_s)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should automatically parse ISO 8601 format dates" do
|
101
|
+
d = Date.today
|
102
|
+
client = EmptyExample.new(test: d.iso8601)
|
103
|
+
expect(client["test"]).to be_an_instance_of(Date)
|
104
|
+
expect(client["test"]).to eq(d)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should automatically parse date/time strings regardless if the date portion has no delimiters" do
|
108
|
+
client = EmptyExample.new(test: "20151230T09:48:50-05:00")
|
109
|
+
expect(client["test"]).to be_an_instance_of(DateTime)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should allow strings of 4 digits and not intepret them as dates" do
|
113
|
+
client = EmptyExample.new(test: "2015")
|
114
|
+
expect(client["test"]).to be_an_instance_of(String)
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should allow strings of 8 digits and not intepret them as dates" do
|
118
|
+
client = EmptyExample.new(test: "1266129")
|
119
|
+
expect(client["test"]).to be_an_instance_of(String)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should store attributes set using missing method names and mark them as dirty" do
|
123
|
+
client = EmptyExample.new()
|
124
|
+
client.test = "Something"
|
125
|
+
expect(client.test.to_s).to eq("Something")
|
126
|
+
expect(client).to be_dirty
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should store attribute set using []= array notation and mark them as dirty" do
|
130
|
+
client = EmptyExample.new()
|
131
|
+
client["test"] = "Something"
|
132
|
+
expect(client["test"].to_s).to eq("Something")
|
133
|
+
expect(client).to be_dirty
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should track changed attributes and provide access to previous values (similar to ActiveRecord/Mongoid)" do
|
137
|
+
client = EmptyExample.new()
|
138
|
+
client["test"] = "Something"
|
139
|
+
|
140
|
+
client._clean! # force a clean state so we can proceed with tests
|
141
|
+
|
142
|
+
expect(client).to_not be_dirty # clean state should have set in (dirty?)
|
143
|
+
expect(client).to_not be_changed # clean state should have set in (changed?)
|
144
|
+
expect(client["test"].to_s).to eq("Something") # verify attribute value persists
|
145
|
+
|
146
|
+
client["test"] = "SomethingElse" # change the attribute value
|
147
|
+
expect(client["test"].to_s).to eq("SomethingElse") # most current set value should be returned
|
148
|
+
expect(client).to be_dirty # an attribute was changed, so the entire object is dirty
|
149
|
+
expect(client).to be_changed # an attribute was changed, so the entire object is changed
|
150
|
+
expect(client.changed).to be_a(Array) # the list of changed attributes should be an Array
|
151
|
+
expect(client.changed).to eq([:test]) # the list of changed attributes should provide the name of the changed attribute
|
152
|
+
expect(client.changes).to be_a(Hash) # changes are returned as a hash
|
153
|
+
expect(client.changes).to eq({test: ["Something", "SomethingElse"]}) # changes include [saved,unsaved] values, keyed by attribute name
|
154
|
+
expect(client.test_was).to eq("Something") # dynamic *_was notation provides original value
|
155
|
+
|
156
|
+
client["test"] = "SomethingElseAgain" # change the attribute value again
|
157
|
+
expect(client.test_was).to eq("Something") # dynamic *_was notation provides original value (from most recent save/load, not most recent change)
|
158
|
+
expect(client.changes).to eq({test: ["Something", "SomethingElseAgain"]}) # changes include [saved,unsaved] values, keyed by attribute name
|
159
|
+
|
160
|
+
# resets the test attribute back to the original value
|
161
|
+
expect( client.reset_test! ).to eq(["Something", "SomethingElseAgain"]) # reseting an attribute returns the previous pending changeset
|
162
|
+
expect(client).to_not be_dirty # reseting an attribute should makeit not dirty again
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should overwrite attributes already set and mark them as dirty" do
|
166
|
+
client = EmptyExample.new(hello: "World")
|
167
|
+
client._clean!
|
168
|
+
expect(client).to_not be_dirty
|
169
|
+
|
170
|
+
client.hello = "Everybody"
|
171
|
+
expect(client).to be_dirty
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should respond_to? attributes defined in the response' do
|
175
|
+
client = EmptyExample.new(hello: "World")
|
176
|
+
expect(client.respond_to?(:hello)).to be_truthy
|
177
|
+
expect(client.respond_to?(:world)).to be_falsey
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should save the base URL for the API server" do
|
181
|
+
class BaseExample < Flexirest::Base
|
182
|
+
base_url "https://www.example.com/api/v1"
|
183
|
+
end
|
184
|
+
expect(BaseExample.base_url).to eq("https://www.example.com/api/v1")
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should allow changing the base_url while running" do
|
188
|
+
class OutsideBaseExample < Flexirest::Base ; end
|
189
|
+
|
190
|
+
Flexirest::Base.base_url = "https://www.example.com/api/v1"
|
191
|
+
expect(OutsideBaseExample.base_url).to eq("https://www.example.com/api/v1")
|
192
|
+
|
193
|
+
Flexirest::Base.base_url = "https://www.example.com/api/v2"
|
194
|
+
expect(OutsideBaseExample.base_url).to eq("https://www.example.com/api/v2")
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should include the Mapping module" do
|
198
|
+
expect(EmptyExample).to respond_to(:_calls)
|
199
|
+
expect(EmptyExample).to_not respond_to(:_non_existant)
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should be able to easily clean all attributes" do
|
203
|
+
client = EmptyExample.new(hello:"World", goodbye:"Everyone")
|
204
|
+
expect(client).to be_dirty
|
205
|
+
client._clean!
|
206
|
+
expect(client).to_not be_dirty
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should not overly pollute the instance method namespace to reduce chances of clashing (<13 instance methods)" do
|
210
|
+
instance_methods = EmptyExample.instance_methods - Object.methods
|
211
|
+
instance_methods = instance_methods - instance_methods.grep(/^_/)
|
212
|
+
expect(instance_methods.size).to be < 13
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should raise an exception for missing attributes if whiny_missing is enabled" do
|
216
|
+
expect{EmptyExample.new.first_name}.to raise_error(Flexirest::NoAttributeException)
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should be able to lazy instantiate an object from a prefixed lazy_ method call" do
|
220
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with('/find/1', anything).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
|
221
|
+
example = AlteringClientExample.lazy_find(1)
|
222
|
+
expect(example).to be_an_instance_of(Flexirest::LazyLoader)
|
223
|
+
expect(example.first_name).to eq("Billy")
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should be able to lazy instantiate an object from a prefixed lazy_ method call from an instance" do
|
227
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with('/find/1', anything).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
|
228
|
+
example = AlteringClientExample.new.lazy_find(1)
|
229
|
+
expect(example).to be_an_instance_of(Flexirest::LazyLoader)
|
230
|
+
expect(example.first_name).to eq("Billy")
|
231
|
+
end
|
232
|
+
|
233
|
+
context "#inspect output" do
|
234
|
+
it "displays a nice version" do
|
235
|
+
object = EmptyExample.new(id: 1, name: "John Smith")
|
236
|
+
expect(object.inspect).to match(/#<EmptyExample id: 1, name: "John Smith"/)
|
237
|
+
end
|
238
|
+
|
239
|
+
it "shows dirty attributes as a list of names at the end" do
|
240
|
+
object = EmptyExample.new(id: 1, name: "John Smith")
|
241
|
+
expect(object.inspect).to match(/#<EmptyExample id: 1, name: "John Smith" \(unsaved: id, name\)/)
|
242
|
+
end
|
243
|
+
|
244
|
+
it "doesn't show an empty list of dirty attributes" do
|
245
|
+
object = EmptyExample.new(id: 1, name: "John Smith")
|
246
|
+
object.instance_variable_set(:@dirty_attributes, Set.new)
|
247
|
+
expect(object.inspect).to_not match(/\(unsaved: id, name\)/)
|
248
|
+
end
|
249
|
+
|
250
|
+
it "shows dates in a nice format" do
|
251
|
+
object = EmptyExample.new(dob: Time.new(2015, 01, 02, 03, 04, 05))
|
252
|
+
expect(object.inspect).to match(/#<EmptyExample dob: "2015\-01\-02 03:04:05"/)
|
253
|
+
end
|
254
|
+
|
255
|
+
it "shows the etag if one is set" do
|
256
|
+
object = EmptyExample.new(id: 1)
|
257
|
+
object.instance_variable_set(:@_etag, "sample_etag")
|
258
|
+
expect(object.inspect).to match(/#<EmptyExample id: 1, ETag: sample_etag/)
|
259
|
+
end
|
260
|
+
|
261
|
+
it "shows the HTTP status code if one is set" do
|
262
|
+
object = EmptyExample.new(id: 1)
|
263
|
+
object.instance_variable_set(:@_status, 200)
|
264
|
+
expect(object.inspect).to match(/#<EmptyExample id: 1, Status: 200/)
|
265
|
+
end
|
266
|
+
|
267
|
+
it "shows [uninitialized] for new objects" do
|
268
|
+
object = EmptyExample.new
|
269
|
+
expect(object.inspect).to match(/#<EmptyExample \[uninitialized\]/)
|
270
|
+
end
|
271
|
+
|
272
|
+
it "truncates the long Strings" do
|
273
|
+
object = EmptyExample.new(id: 1, name: "x" * 100)
|
274
|
+
expect(object.inspect).to match(/#<EmptyExample id: 1, name: "x{51}\.\.\."/)
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
|
279
|
+
context "accepts a Translator to reformat JSON" do
|
280
|
+
it "should log a deprecation warning when using a translator" do
|
281
|
+
expect(Flexirest::Logger).to receive(:warn) do |message|
|
282
|
+
expect(message).to start_with("DEPRECATION")
|
283
|
+
end
|
284
|
+
Proc.new do
|
285
|
+
class DummyExample < Flexirest::Base
|
286
|
+
translator TranslatorExample
|
287
|
+
end
|
288
|
+
end.call
|
289
|
+
end
|
290
|
+
|
291
|
+
it "should call Translator#method when calling the mapped method if it responds to it" do
|
292
|
+
expect(TranslatorExample).to receive(:all).with(an_instance_of(Hash)).and_return({})
|
293
|
+
AlteringClientExample.all
|
294
|
+
end
|
295
|
+
|
296
|
+
it "should not raise errors when calling Translator#method if it does not respond to it" do
|
297
|
+
expect {AlteringClientExample.list}.to_not raise_error
|
298
|
+
end
|
299
|
+
|
300
|
+
it "should translate JSON returned through the Translator" do
|
301
|
+
ret = AlteringClientExample.all
|
302
|
+
expect(ret.first_name).to eq("Billy")
|
303
|
+
expect(ret.name).to be_nil
|
304
|
+
end
|
305
|
+
|
306
|
+
it "should return original JSON for items that aren't handled by the Translator" do
|
307
|
+
ret = AlteringClientExample.list
|
308
|
+
expect(ret.name).to eq("Billy")
|
309
|
+
expect(ret.first_name).to be_nil
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
context "directly call a URL, rather than via a mapped method" do
|
314
|
+
it "should be able to directly call a URL" do
|
315
|
+
expect_any_instance_of(Flexirest::Request).to receive(:do_request).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
|
316
|
+
EmptyExample._request("http://api.example.com/")
|
317
|
+
end
|
318
|
+
|
319
|
+
it "allows already encoded bodies" do
|
320
|
+
Flexirest::ConnectionManager.reset!
|
321
|
+
connection = double("Connection")
|
322
|
+
allow(connection).to receive(:base_url).and_return("http://api.example.com")
|
323
|
+
expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://api.example.com/").and_return(connection)
|
324
|
+
expect(connection).
|
325
|
+
to receive(:post).
|
326
|
+
with("http://api.example.com/", "{\"test\":\"value\"}",an_instance_of(Hash)).
|
327
|
+
and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"first_name\":\"John\", \"id\":1234}", response_headers:{}, status:200)))
|
328
|
+
EmptyExample._request("http://api.example.com/", :post, {test: "value"}.to_json, request_body_type: :json)
|
329
|
+
end
|
330
|
+
|
331
|
+
it "passes headers" do
|
332
|
+
stub_request(:get, "http://api.example.com/v1").
|
333
|
+
with(headers: {'Accept'=>'application/hal+json, application/json;q=0.5', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Connection'=>'Keep-Alive', 'Content-Type'=>'application/x-www-form-urlencoded', 'X-Something'=>'foo/bar', 'User-Agent'=>/Flexirest\//}).
|
334
|
+
to_return(status: 200, body: "", headers: {})
|
335
|
+
EmptyExample._request("http://api.example.com/v1", :get, {}, {headers: {"X-Something" => "foo/bar"}})
|
336
|
+
end
|
337
|
+
|
338
|
+
it "passes headers if the response is unparsed" do
|
339
|
+
stub_request(:get, "http://api.example.com/v1").
|
340
|
+
with(headers: {'Accept'=>'application/hal+json, application/json;q=0.5', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Connection'=>'Keep-Alive', 'Content-Type'=>'application/x-www-form-urlencoded', 'X-Something'=>'foo/bar', 'User-Agent'=>/Flexirest\//}).
|
341
|
+
to_return(status: 200, body: "", headers: {})
|
342
|
+
EmptyExample._plain_request("http://api.example.com/v1", :get, {}, {headers: {"X-Something" => "foo/bar"}})
|
343
|
+
end
|
344
|
+
|
345
|
+
it "runs callbacks as usual" do
|
346
|
+
expect_any_instance_of(Flexirest::Request).to receive(:do_request).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
|
347
|
+
expect(EmptyExample).to receive(:_callback_request).with(any_args).exactly(2).times
|
348
|
+
EmptyExample._request("http://api.example.com/")
|
349
|
+
end
|
350
|
+
|
351
|
+
it "should make an HTTP request" do
|
352
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
|
353
|
+
EmptyExample._request("http://api.example.com/")
|
354
|
+
end
|
355
|
+
|
356
|
+
it "should make an HTTP request including the path in the base_url" do
|
357
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with('/v1/all', anything).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
|
358
|
+
NonHostnameBaseUrlExample.all
|
359
|
+
end
|
360
|
+
|
361
|
+
it "should map the response from the directly called URL in the normal way" do
|
362
|
+
expect_any_instance_of(Flexirest::Request).to receive(:do_request).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
|
363
|
+
example = EmptyExample._request("http://api.example.com/")
|
364
|
+
expect(example.first_name).to eq("Billy")
|
365
|
+
end
|
366
|
+
|
367
|
+
it "should be able to pass the plain response from the directly called URL bypassing JSON loading" do
|
368
|
+
response_body = "This is another non-JSON string"
|
369
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:post).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:response_body)))
|
370
|
+
expect(EmptyExample._plain_request("http://api.example.com/", :post, {id:1234})).to eq(response_body)
|
371
|
+
end
|
372
|
+
|
373
|
+
it "should return a PlainResponse from the directly called URL bypassing JSON loading" do
|
374
|
+
response_body = "This is another non-JSON string"
|
375
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:post).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:response_body)))
|
376
|
+
expect(EmptyExample._plain_request("http://api.example.com/", :post, {id:1234})).to be_a(Flexirest::PlainResponse)
|
377
|
+
end
|
378
|
+
|
379
|
+
context "Simulating Faraday connection in_parallel" do
|
380
|
+
it "should be able to pass the plain response from the directly called URL bypassing JSON loading" do
|
381
|
+
response_body = "This is another non-JSON string"
|
382
|
+
response = ::FaradayResponseMock.new(
|
383
|
+
OpenStruct.new(status:200, response_headers:{}, body:response_body),
|
384
|
+
false)
|
385
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:post).with(any_args).and_return(response)
|
386
|
+
result = EmptyExample._plain_request("http://api.example.com/", :post, {id:1234})
|
387
|
+
|
388
|
+
expect(result).to eq(nil)
|
389
|
+
|
390
|
+
response.finish
|
391
|
+
expect(result).to eq(response_body)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
it "should cache plain requests separately" do
|
396
|
+
perform_caching = EmptyExample.perform_caching
|
397
|
+
cache_store = EmptyExample.cache_store
|
398
|
+
begin
|
399
|
+
response = "This is a non-JSON string"
|
400
|
+
other_response = "This is another non-JSON string"
|
401
|
+
allow_any_instance_of(Flexirest::Connection).to receive(:get) do |instance, url, others|
|
402
|
+
if url["/?test=1"]
|
403
|
+
::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:response))
|
404
|
+
else
|
405
|
+
::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:other_response))
|
406
|
+
end
|
407
|
+
end
|
408
|
+
EmptyExample.perform_caching = true
|
409
|
+
EmptyExample.cache_store = TestCacheStore.new
|
410
|
+
expect(EmptyExample._plain_request("http://api.example.com/?test=1")).to eq(response)
|
411
|
+
expect(EmptyExample._plain_request("http://api.example.com/?test=2")).to eq(other_response)
|
412
|
+
ensure
|
413
|
+
EmptyExample.perform_caching = perform_caching
|
414
|
+
EmptyExample.cache_store = cache_store
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
it "should work with caching if instance methods are used" do
|
419
|
+
perform_caching = InstanceMethodExample.perform_caching
|
420
|
+
cache_store = InstanceMethodExample.cache_store
|
421
|
+
begin
|
422
|
+
response = "{\"id\": 1, \"name\":\"test\"}"
|
423
|
+
allow_any_instance_of(Flexirest::Connection).to receive(:get).and_return( ::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{"Etag" => "12345678", "Content-type" => "application/json"}, body:response)))
|
424
|
+
e = InstanceMethodExample.new
|
425
|
+
e.all(1)
|
426
|
+
expect(e.id).to eq(1)
|
427
|
+
ensure
|
428
|
+
InstanceMethodExample.perform_caching = perform_caching
|
429
|
+
InstanceMethodExample.cache_store = cache_store
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
it "should be able to lazy load a direct URL request" do
|
434
|
+
expect_any_instance_of(Flexirest::Request).to receive(:do_request).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
|
435
|
+
example = EmptyExample._lazy_request("http://api.example.com/")
|
436
|
+
expect(example).to be_an_instance_of(Flexirest::LazyLoader)
|
437
|
+
expect(example.first_name).to eq("Billy")
|
438
|
+
end
|
439
|
+
|
440
|
+
it "should be able to specify a method and parameters for the call" do
|
441
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:post).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
|
442
|
+
EmptyExample._request("http://api.example.com/", :post, {id:1234})
|
443
|
+
end
|
444
|
+
|
445
|
+
it "should be able to replace parameters in the URL for the call" do
|
446
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:post).with("http://api.example.com/1234", "", any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
|
447
|
+
EmptyExample._request("http://api.example.com/:id", :post, {id:1234})
|
448
|
+
end
|
449
|
+
|
450
|
+
it "should be able to use mapped methods to create a request to pass in to _lazy_request" do
|
451
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with('/find/1', anything).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"{\"first_name\":\"Billy\"}")))
|
452
|
+
request = AlteringClientExample._request_for(:find, id: 1)
|
453
|
+
example = AlteringClientExample._lazy_request(request)
|
454
|
+
expect(example.first_name).to eq("Billy")
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
context "Recording a response" do
|
459
|
+
it "calls back to the record_response callback with the url and response body" do
|
460
|
+
expect_any_instance_of(Flexirest::Connection).to receive(:get).with(any_args).and_return(::FaradayResponseMock.new(OpenStruct.new(status:200, response_headers:{}, body:"Hello world")))
|
461
|
+
expect{RecordResponseExample.all}.to raise_error(Exception, "/all|Hello world")
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
context "JSON output" do
|
466
|
+
let(:student1) { EmptyExample.new(name:"John Smith", age:31) }
|
467
|
+
let(:student2) { EmptyExample.new(name:"Bob Brown", age:29) }
|
468
|
+
let(:location) { EmptyExample.new(place:"Room 1408") }
|
469
|
+
let(:lazy) { Laz }
|
470
|
+
let(:object) { EmptyExample.new(name:"Programming 101", location:location, students:[student1, student2]) }
|
471
|
+
let(:json_parsed_object) { MultiJson.load(object.to_json) }
|
472
|
+
|
473
|
+
it "should be able to export to valid json" do
|
474
|
+
expect(object.to_json).to_not be_blank
|
475
|
+
expect{MultiJson.load(object.to_json)}.to_not raise_error
|
476
|
+
end
|
477
|
+
|
478
|
+
it "should not be using Object's #to_json method" do
|
479
|
+
expect(json_parsed_object["dirty_attributes"]).to be_nil
|
480
|
+
end
|
481
|
+
|
482
|
+
it "should recursively convert nested objects" do
|
483
|
+
expect(json_parsed_object["location"]["place"]).to eq(location.place)
|
484
|
+
end
|
485
|
+
|
486
|
+
it "should include arrayed objects" do
|
487
|
+
expect(json_parsed_object["students"]).to be_an_instance_of(Array)
|
488
|
+
expect(json_parsed_object["students"].size).to eq(2)
|
489
|
+
expect(json_parsed_object["students"].first["name"]).to eq(student1.name)
|
490
|
+
expect(json_parsed_object["students"].second["name"]).to eq(student2.name)
|
491
|
+
end
|
492
|
+
|
493
|
+
it "should set integers as a native JSON type" do
|
494
|
+
expect(json_parsed_object["students"].first["age"]).to eq(student1.age)
|
495
|
+
expect(json_parsed_object["students"].second["age"]).to eq(student2.age)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
describe "instantiating object" do
|
500
|
+
context "no whitelist specified" do
|
501
|
+
it "should convert dates automatically" do
|
502
|
+
client = EmptyExample.new(test: Time.now.iso8601)
|
503
|
+
expect(client["test"]).to be_an_instance_of(DateTime)
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
context "whitelist specified" do
|
508
|
+
it "should only convert specified dates" do
|
509
|
+
time = Time.now.iso8601
|
510
|
+
client = WhitelistedDateExample.new(updated_at: time, created_at: time)
|
511
|
+
expect(client["updated_at"]).to be_an_instance_of(DateTime)
|
512
|
+
expect(client["created_at"]).to be_an_instance_of(String)
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
end
|