flexirest 1.6.7 → 1.6.8

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.
@@ -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