ddy_remote_resource 0.4.11 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/Guardfile +3 -0
  4. data/lib/remote_resource.rb +77 -34
  5. data/lib/remote_resource/base.rb +20 -8
  6. data/lib/remote_resource/connection.rb +26 -5
  7. data/lib/remote_resource/connection_options.rb +5 -3
  8. data/lib/remote_resource/querying/finder_methods.rb +3 -3
  9. data/lib/remote_resource/querying/persistence_methods.rb +17 -12
  10. data/lib/remote_resource/request.rb +96 -62
  11. data/lib/remote_resource/response.rb +5 -1
  12. data/lib/remote_resource/rest.rb +13 -17
  13. data/lib/remote_resource/url_naming.rb +4 -10
  14. data/lib/remote_resource/url_naming_determination.rb +1 -3
  15. data/lib/remote_resource/util.rb +64 -0
  16. data/lib/remote_resource/version.rb +1 -1
  17. data/remote_resource.gemspec +2 -2
  18. data/spec/fixtures/text_file.txt +1 -0
  19. data/spec/integration/all_spec.rb +166 -0
  20. data/spec/integration/collection_prefix_spec.rb +99 -0
  21. data/spec/integration/create_spec.rb +181 -0
  22. data/spec/integration/destroy_spec.rb +252 -0
  23. data/spec/integration/find_by_spec.rb +168 -0
  24. data/spec/integration/find_spec.rb +139 -0
  25. data/spec/integration/headers_spec.rb +222 -0
  26. data/spec/integration/naming_spec.rb +138 -0
  27. data/spec/integration/save_spec.rb +320 -0
  28. data/spec/integration/update_attributes_spec.rb +221 -0
  29. data/spec/integration/where_spec.rb +152 -0
  30. data/spec/lib/extensions/ethon/easy/queryable_spec.rb +4 -4
  31. data/spec/lib/remote_resource/base_spec.rb +54 -110
  32. data/spec/lib/remote_resource/builder_spec.rb +1 -1
  33. data/spec/lib/remote_resource/collection_spec.rb +1 -1
  34. data/spec/lib/remote_resource/connection_options_spec.rb +20 -17
  35. data/spec/lib/remote_resource/connection_spec.rb +36 -27
  36. data/spec/lib/remote_resource/querying/finder_methods_spec.rb +199 -72
  37. data/spec/lib/remote_resource/querying/persistence_methods_spec.rb +228 -220
  38. data/spec/lib/remote_resource/request_spec.rb +313 -342
  39. data/spec/lib/remote_resource/response_spec.rb +9 -3
  40. data/spec/lib/remote_resource/rest_spec.rb +11 -11
  41. data/spec/lib/remote_resource/url_naming_determination_spec.rb +1 -1
  42. data/spec/lib/remote_resource/url_naming_spec.rb +7 -22
  43. data/spec/lib/remote_resource/util_spec.rb +56 -0
  44. data/spec/lib/remote_resource/version_spec.rb +2 -3
  45. data/spec/spec_helper.rb +37 -0
  46. metadata +33 -22
  47. data/lib/remote_resource/http_errors.rb +0 -33
  48. data/lib/remote_resource/response_handeling.rb +0 -48
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe RemoteResource::Connection do
3
+ RSpec.describe RemoteResource::Connection do
4
4
 
5
5
  module RemoteResource
6
6
  class ConnectionDummy
@@ -20,42 +20,51 @@ describe RemoteResource::Connection do
20
20
  end
21
21
  end
22
22
 
23
- describe '.content_type' do
24
- let!(:original_content_type) { dummy_class.content_type }
25
-
26
- context 'when content_type is set' do
27
- it 'returns the given content_type' do
28
- dummy_class.content_type = '.html'
29
-
30
- expect(dummy_class.content_type).to eql '.html'
23
+ describe '.default_headers' do
24
+ it 'returns an empty Hash' do
25
+ expect(dummy_class.default_headers).to eql({})
26
+ end
27
+ end
31
28
 
32
- dummy_class.content_type = original_content_type
33
- end
29
+ describe '.content_type=' do
30
+ it 'warns that the method is deprecated' do
31
+ expect(dummy_class).to receive(:warn).with('[DEPRECATION] `.content_type=` is deprecated. Please use `.extension=` instead.')
32
+ dummy_class.content_type = '.json'
34
33
  end
34
+ end
35
35
 
36
- context 'when NO content_type is set' do
37
- it 'returns the default content_type' do
38
- expect(dummy_class.content_type).to eql '.json'
39
- end
36
+ describe '.content_type' do
37
+ it 'warns that the method is deprecated' do
38
+ expect(dummy_class).to receive(:warn).with('[DEPRECATION] `.content_type` is deprecated. Please use `.extension` instead.')
39
+ dummy_class.content_type
40
40
  end
41
41
  end
42
42
 
43
- describe '.headers' do
44
- context 'when .extra_headers are set' do
45
- it 'returns the default headers merged with the set .extra_headers' do
46
- dummy_class.extra_headers = { "Foo" => "Bar" }
43
+ describe '.extra_headers=' do
44
+ it 'warns that the method is deprecated' do
45
+ expect(dummy_class).to receive(:warn).with('[DEPRECATION] `.extra_headers=` is deprecated. Please overwrite the .headers method to set custom headers.')
46
+ dummy_class.extra_headers = '.json'
47
+ end
48
+ end
47
49
 
48
- expect(dummy_class.headers).to eql({ "Accept" => "application/json", "Foo" => "Bar" })
50
+ describe '.extra_headers' do
51
+ it 'warns that the method is deprecated' do
52
+ expect(dummy_class).to receive(:warn).with('[DEPRECATION] `.extra_headers` is deprecated. Please overwrite the .headers method to set custom headers.')
53
+ dummy_class.extra_headers
54
+ end
55
+ end
49
56
 
50
- dummy_class.extra_headers = nil
51
- end
57
+ describe '.headers=' do
58
+ it 'warns that the method is not used to set custom headers' do
59
+ expect(dummy_class).to receive(:warn).with('[WARNING] `.headers=` can not be used to set custom headers. Please overwrite the .headers method to set custom headers.')
60
+ dummy_class.headers = { 'Foo' => 'Bar' }
52
61
  end
62
+ end
53
63
 
54
- context 'when NO .extra_headers are set' do
55
- it 'returns the default headers' do
56
- expect(dummy_class.headers).to eql({ "Accept" => "application/json" })
57
- end
64
+ describe '.headers' do
65
+ it 'returns an empty Hash' do
66
+ expect(dummy_class.headers).to eql({})
58
67
  end
59
68
  end
60
69
 
61
- end
70
+ end
@@ -1,138 +1,265 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe RemoteResource::Querying::FinderMethods do
3
+ RSpec.describe RemoteResource::Querying::FinderMethods do
4
4
 
5
- module RemoteResource
6
- module Querying
7
- class FinderMethodsDummy
8
- include RemoteResource::Base
5
+ class Post
6
+ include RemoteResource::Base
9
7
 
10
- self.site = 'https://foobar.com'
8
+ self.site = 'https://www.example.com'
9
+ self.collection = true
10
+ self.root_element = :data
11
11
 
12
- end
13
- end
12
+ attribute :title, String
13
+ attribute :body, String
14
+ attribute :featured, Boolean
15
+ attribute :created_at, Time
14
16
  end
15
17
 
16
- let(:dummy_class) { RemoteResource::Querying::FinderMethodsDummy }
17
- let(:dummy) { dummy_class.new }
18
-
19
18
  describe '.find' do
20
- let(:response) { instance_double(RemoteResource::Response) }
19
+ let(:response_body) do
20
+ {
21
+ data: {
22
+ id: 12,
23
+ title: 'Lorem Ipsum',
24
+ body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
25
+ featured: true,
26
+ created_at: Time.new(2015, 10, 4, 9, 30, 0),
27
+ }
28
+ }
29
+ end
21
30
 
22
- before do
23
- allow(dummy_class).to receive(:build_resource_from_response) { dummy }
24
- allow_any_instance_of(RemoteResource::Request).to receive(:perform) { response }
31
+ let!(:expected_request) do
32
+ mock_request = stub_request(:get, 'https://www.example.com/posts/12.json')
33
+ mock_request.to_return(status: 200, body: response_body.to_json)
34
+ mock_request
25
35
  end
26
36
 
27
- it 'performs a RemoteResource::Request with the connection_options no_attributes' do
28
- stub_request(:get, 'https://foobar.com/finder_methods_dummy/12.json').to_return(status: 200, body: {}.to_json)
29
- expect(RemoteResource::Request).to receive(:new).with(dummy_class, :get, { id: '12' }, { no_attributes: true }).and_call_original
30
- expect_any_instance_of(RemoteResource::Request).to receive(:perform).and_call_original
31
- dummy_class.find('12')
37
+ it 'performs the HTTP request' do
38
+ Post.find(12)
39
+ expect(expected_request).to have_been_requested
32
40
  end
33
41
 
34
- it 'builds the resource from the RemoteResource::Response' do
35
- expect(dummy_class).to receive(:build_resource_from_response).with response
36
- dummy_class.find('12')
42
+ it 'builds the correct resource' do
43
+ post = Post.find(12)
44
+
45
+ aggregate_failures do
46
+ expect(post.id).to eql 12
47
+ expect(post.title).to eql 'Lorem Ipsum'
48
+ expect(post.body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
49
+ expect(post.featured).to eql true
50
+ expect(post.created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
51
+ end
37
52
  end
38
53
 
39
54
  it 'does NOT change the given connection_options' do
40
55
  connection_options = { headers: { 'Foo' => 'Bar' } }
41
56
 
42
- expect { dummy_class.find('12', connection_options) }.not_to change { connection_options }.from({ headers: { 'Foo' => 'Bar' } })
57
+ expect { Post.find(12, connection_options) }.not_to change { connection_options }.from(connection_options.dup)
43
58
  end
44
59
 
45
- context 'with extra params' do
46
- it 'performs a RemoteResource::Request with params' do
47
- stub_request(:get, 'https://foobar.com/finder_methods_dummy/12.json?skip_associations=true').to_return(status: 200, body: {}.to_json)
48
- expect(RemoteResource::Request).to receive(:new).with(dummy_class, :get, { id: '12' }, { params: { skip_associations: true }, no_attributes: true }).and_call_original
49
- expect_any_instance_of(RemoteResource::Request).to receive(:perform).and_call_original
50
- dummy_class.find('12', params: { skip_associations: true })
51
- end
60
+ xcontext 'return value #success? and NOT #success?' do
52
61
  end
53
62
  end
54
63
 
55
64
  describe '.find_by' do
56
- let(:response) { instance_double(RemoteResource::Response) }
57
- let(:params) do
58
- { id: '12' }
65
+ let(:response_body) do
66
+ {
67
+ data: {
68
+ id: 12,
69
+ title: 'Lorem Ipsum',
70
+ body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
71
+ featured: true,
72
+ created_at: Time.new(2015, 10, 4, 9, 30, 0),
73
+ }
74
+ }
59
75
  end
60
76
 
61
- before do
62
- allow(dummy_class).to receive(:build_resource_from_response) { dummy }
63
- allow_any_instance_of(RemoteResource::Request).to receive(:perform) { response }
77
+ let!(:expected_request) do
78
+ mock_request = stub_request(:get, 'https://www.example.com/posts/current.json')
79
+ mock_request.with(query: { title: 'Lorem Ipsum', featured: true })
80
+ mock_request.to_return(status: 200, body: response_body.to_json)
81
+ mock_request
64
82
  end
65
83
 
66
- it 'performs a RemoteResource::Request' do
67
- expect(RemoteResource::Request).to receive(:new).with(dummy_class, :get, params, {}).and_call_original
68
- expect_any_instance_of(RemoteResource::Request).to receive(:perform)
69
- dummy_class.find_by params
84
+ it 'performs the HTTP request' do
85
+ Post.find_by({ title: 'Lorem Ipsum', featured: true }, path_postfix: '/current')
86
+ expect(expected_request).to have_been_requested
70
87
  end
71
88
 
72
- it 'builds the resource from the RemoteResource::Response' do
73
- expect(dummy_class).to receive(:build_resource_from_response).with response
74
- dummy_class.find_by params
89
+ it 'builds the correct resource' do
90
+ post = Post.find_by({ title: 'Lorem Ipsum', featured: true }, path_postfix: '/current')
91
+
92
+ aggregate_failures do
93
+ expect(post.id).to eql 12
94
+ expect(post.title).to eql 'Lorem Ipsum'
95
+ expect(post.body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
96
+ expect(post.featured).to eql true
97
+ expect(post.created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
98
+ end
99
+ end
100
+
101
+ it 'does NOT change the given params' do
102
+ params = { title: 'Lorem Ipsum', featured: true }
103
+
104
+ expect { Post.find_by(params, path_postfix: '/current') }.not_to change { params }.from(params.dup)
75
105
  end
76
106
 
77
107
  it 'does NOT change the given connection_options' do
78
- connection_options = { headers: { 'Foo' => 'Bar' } }
108
+ params = { title: 'Lorem Ipsum', featured: true }
109
+ connection_options = { path_postfix: '/current', headers: { 'Foo' => 'Bar' } }
110
+
111
+ expect { Post.find_by(params, connection_options) }.not_to change { connection_options }.from(connection_options.dup)
112
+ end
79
113
 
80
- expect { dummy_class.find_by(params, connection_options) }.not_to change { connection_options }.from({ headers: { 'Foo' => 'Bar' } })
114
+ xcontext 'return value #success? and NOT #success?' do
81
115
  end
82
116
  end
83
117
 
84
118
  describe '.all' do
85
- let(:response) { instance_double(RemoteResource::Response) }
119
+ let(:response_body) do
120
+ {
121
+ data: [
122
+ {
123
+ id: 12,
124
+ title: 'Lorem Ipsum',
125
+ body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
126
+ created_at: Time.new(2015, 10, 4, 9, 30, 0),
127
+ },
128
+ {
129
+ id: 14,
130
+ title: 'Mauris Purus',
131
+ body: 'Mauris purus urna, ultrices et suscipit ut, faucibus eget mauris.',
132
+ created_at: Time.new(2015, 12, 11, 11, 32, 0),
133
+ },
134
+ {
135
+ id: 16,
136
+ title: 'Vestibulum Commodo',
137
+ body: 'Vestibulum commodo fringilla suscipit.',
138
+ created_at: Time.new(2016, 2, 6, 18, 45, 0),
139
+ },
140
+ ]
141
+ }
142
+ end
86
143
 
87
- before do
88
- allow(dummy_class).to receive(:build_collection_from_response) { dummy }
89
- allow_any_instance_of(RemoteResource::Request).to receive(:perform) { response }
144
+ let!(:expected_request) do
145
+ mock_request = stub_request(:get, 'https://www.example.com/posts.json')
146
+ mock_request.to_return(status: 200, body: response_body.to_json)
147
+ mock_request
90
148
  end
91
149
 
92
- it 'performs a RemoteResource::Request with the connection_options collection' do
93
- expect(RemoteResource::Request).to receive(:new).with(dummy_class, :get, {}, { collection: true }).and_call_original
94
- expect_any_instance_of(RemoteResource::Request).to receive(:perform)
95
- dummy_class.all
150
+ it 'performs the HTTP request' do
151
+ Post.all
152
+ expect(expected_request).to have_been_requested
96
153
  end
97
154
 
98
- it 'builds the resources from the RemoteResource::Response' do
99
- expect(dummy_class).to receive(:build_collection_from_response).with response
100
- dummy_class.all
155
+ it 'builds the correct collection of resources' do
156
+ posts = Post.all
157
+
158
+ aggregate_failures do
159
+ expect(posts).to respond_to :each
160
+ expect(posts).to all(be_a(Post))
161
+ expect(posts.size).to eql 3
162
+
163
+ expect(posts[0].id).to eql 12
164
+ expect(posts[0].title).to eql 'Lorem Ipsum'
165
+ expect(posts[0].body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
166
+ expect(posts[0].created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
167
+ expect(posts[1].id).to eql 14
168
+ expect(posts[1].title).to eql 'Mauris Purus'
169
+ expect(posts[1].body).to eql 'Mauris purus urna, ultrices et suscipit ut, faucibus eget mauris.'
170
+ expect(posts[1].created_at).to eql Time.new(2015, 12, 11, 11, 32, 0)
171
+ expect(posts[2].id).to eql 16
172
+ expect(posts[2].title).to eql 'Vestibulum Commodo'
173
+ expect(posts[2].body).to eql 'Vestibulum commodo fringilla suscipit.'
174
+ expect(posts[2].created_at).to eql Time.new(2016, 2, 6, 18, 45, 0)
175
+ end
101
176
  end
102
177
 
103
178
  it 'does NOT change the given connection_options' do
104
179
  connection_options = { headers: { 'Foo' => 'Bar' } }
105
180
 
106
- expect { dummy_class.all(connection_options) }.not_to change { connection_options }.from({ headers: { 'Foo' => 'Bar' } })
181
+ expect { Post.all(connection_options) }.not_to change { connection_options }.from(connection_options.dup)
182
+ end
183
+
184
+ xcontext 'return value #success? and NOT #success?' do
107
185
  end
108
186
  end
109
187
 
110
188
  describe '.where' do
111
- let(:response) { instance_double(RemoteResource::Response) }
112
- let(:params) do
113
- { username: 'mies' }
189
+ let(:response_body) do
190
+ {
191
+ data: [
192
+ {
193
+ id: 12,
194
+ title: 'Lorem Ipsum',
195
+ body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
196
+ created_at: Time.new(2015, 10, 4, 9, 30, 0),
197
+ },
198
+ {
199
+ id: 14,
200
+ title: 'Mauris Purus',
201
+ body: 'Mauris purus urna, ultrices et suscipit ut, faucibus eget mauris.',
202
+ created_at: Time.new(2015, 12, 11, 11, 32, 0),
203
+ },
204
+ {
205
+ id: 16,
206
+ title: 'Vestibulum Commodo',
207
+ body: 'Vestibulum commodo fringilla suscipit.',
208
+ created_at: Time.new(2016, 2, 6, 18, 45, 0),
209
+ },
210
+ ]
211
+ }
212
+ end
213
+
214
+ let!(:expected_request) do
215
+ mock_request = stub_request(:get, 'https://www.example.com/posts.json')
216
+ mock_request.with(query: { pseudonym: 'pseudonym' })
217
+ mock_request.to_return(status: 200, body: response_body.to_json)
218
+ mock_request
114
219
  end
115
220
 
116
- before do
117
- allow(dummy_class).to receive(:build_collection_from_response) { dummy }
118
- allow_any_instance_of(RemoteResource::Request).to receive(:perform) { response }
221
+ it 'performs the HTTP request' do
222
+ Post.where({ pseudonym: 'pseudonym' })
223
+ expect(expected_request).to have_been_requested
119
224
  end
120
225
 
121
- it 'performs a RemoteResource::Request with the connection_options collection' do
122
- expect(RemoteResource::Request).to receive(:new).with(dummy_class, :get, params, { collection: true }).and_call_original
123
- expect_any_instance_of(RemoteResource::Request).to receive(:perform)
124
- dummy_class.where params
226
+ it 'builds the correct collection of resources' do
227
+ posts = Post.where({ pseudonym: 'pseudonym' })
228
+
229
+ aggregate_failures do
230
+ expect(posts).to respond_to :each
231
+ expect(posts).to all(be_a(Post))
232
+ expect(posts.size).to eql 3
233
+
234
+ expect(posts[0].id).to eql 12
235
+ expect(posts[0].title).to eql 'Lorem Ipsum'
236
+ expect(posts[0].body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
237
+ expect(posts[0].created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
238
+ expect(posts[1].id).to eql 14
239
+ expect(posts[1].title).to eql 'Mauris Purus'
240
+ expect(posts[1].body).to eql 'Mauris purus urna, ultrices et suscipit ut, faucibus eget mauris.'
241
+ expect(posts[1].created_at).to eql Time.new(2015, 12, 11, 11, 32, 0)
242
+ expect(posts[2].id).to eql 16
243
+ expect(posts[2].title).to eql 'Vestibulum Commodo'
244
+ expect(posts[2].body).to eql 'Vestibulum commodo fringilla suscipit.'
245
+ expect(posts[2].created_at).to eql Time.new(2016, 2, 6, 18, 45, 0)
246
+ end
125
247
  end
126
248
 
127
- it 'builds the resources from the RemoteResource::Response' do
128
- expect(dummy_class).to receive(:build_collection_from_response).with response
129
- dummy_class.where params
249
+ it 'does NOT change the given params' do
250
+ params = { pseudonym: 'pseudonym' }
251
+
252
+ expect { Post.where(params) }.not_to change { params }.from(params.dup)
130
253
  end
131
254
 
132
255
  it 'does NOT change the given connection_options' do
256
+ params = { pseudonym: 'pseudonym' }
133
257
  connection_options = { headers: { 'Foo' => 'Bar' } }
134
258
 
135
- expect { dummy_class.where(params, connection_options) }.not_to change { connection_options }.from({ headers: { 'Foo' => 'Bar' } })
259
+ expect { Post.where(params, connection_options) }.not_to change { connection_options }.from(connection_options.dup)
260
+ end
261
+
262
+ xcontext 'return value #success? and NOT #success?' do
136
263
  end
137
264
  end
138
265
 
@@ -1,342 +1,350 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe RemoteResource::Querying::PersistenceMethods do
3
+ RSpec.describe RemoteResource::Querying::PersistenceMethods do
4
4
 
5
- module RemoteResource
6
- module Querying
7
- class PersistenceMethodsDummy
8
- include RemoteResource::Base
5
+ class Post
6
+ include RemoteResource::Base
9
7
 
10
- self.site = 'https://foobar.com'
8
+ self.site = 'https://www.example.com'
9
+ self.collection = true
10
+ self.root_element = :data
11
11
 
12
- attribute :name
13
-
14
- end
15
- end
12
+ attribute :title, String
13
+ attribute :body, String
14
+ attribute :featured, Boolean
15
+ attribute :created_at, Time
16
16
  end
17
17
 
18
- let(:dummy_class) { RemoteResource::Querying::PersistenceMethodsDummy }
19
- let(:dummy) { dummy_class.new }
20
-
21
18
  describe '.create' do
22
- let(:response) { instance_double(RemoteResource::Response) }
23
- let(:attributes) do
24
- { name: 'Mies' }
25
- end
26
-
27
- before do
28
- allow_any_instance_of(dummy_class).to receive(:handle_response)
29
- allow_any_instance_of(RemoteResource::Request).to receive(:perform) { response }
30
- end
31
-
32
- it 'instantiates the resource with the attributes' do
33
- expect(dummy_class).to receive(:new).with(attributes).and_call_original
34
- dummy_class.create attributes
35
- end
36
-
37
- it 'performs a RemoteResource::Request' do
38
- expect(RemoteResource::Request).to receive(:new).with(dummy_class, :post, attributes, {}).and_call_original
39
- expect_any_instance_of(RemoteResource::Request).to receive(:perform)
40
- dummy_class.create attributes
41
- end
42
-
43
- it 'handles the RemoteResource::Response' do
44
- expect_any_instance_of(dummy_class).to receive(:handle_response).with response
45
- dummy_class.create attributes
19
+ let(:response_body) do
20
+ {
21
+ data: {
22
+ id: 12,
23
+ title: 'Lorem Ipsum',
24
+ body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
25
+ featured: true,
26
+ created_at: Time.new(2015, 10, 4, 9, 30, 0),
27
+ }
28
+ }
29
+ end
30
+
31
+ let!(:expected_request) do
32
+ mock_request = stub_request(:post, 'https://www.example.com/posts.json')
33
+ mock_request.to_return(status: 201, body: JSON.generate(response_body))
34
+ mock_request
35
+ end
36
+
37
+ it 'performs the HTTP request' do
38
+ Post.create(title: 'Lorem Ipsum', body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', featured: true)
39
+ expect(expected_request).to have_been_requested
40
+ end
41
+
42
+ it 'builds the correct resource' do
43
+ post = Post.create(title: 'Lorem Ipsum', body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', featured: true)
44
+
45
+ aggregate_failures do
46
+ expect(post.persisted?).to eql true
47
+ expect(post.id).to eql 12
48
+ expect(post.title).to eql 'Lorem Ipsum'
49
+ expect(post.body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
50
+ expect(post.featured).to eql true
51
+ expect(post.created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
52
+ end
46
53
  end
47
54
 
48
55
  it 'does NOT change the given attributes' do
49
- expect { dummy_class.create(attributes) }.not_to change { attributes }.from({ name: 'Mies' })
56
+ attributes = { title: 'Lorem Ipsum', body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', featured: true }
57
+
58
+ expect { Post.create(attributes) }.not_to change { attributes }.from(attributes.dup)
50
59
  end
51
60
 
52
61
  it 'does NOT change the given connection_options' do
62
+ attributes = { title: 'Lorem Ipsum', body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', featured: true }
53
63
  connection_options = { headers: { 'Foo' => 'Bar' } }
54
64
 
55
- expect { dummy_class.create(attributes, connection_options) }.not_to change { connection_options }.from({ headers: { 'Foo' => 'Bar' } })
65
+ expect { Post.create(attributes, connection_options) }.not_to change { connection_options }.from(connection_options.dup)
66
+ end
67
+
68
+ xcontext 'return value #success? and NOT #success?' do
56
69
  end
57
70
  end
58
71
 
59
72
  describe '.destroy' do
60
- let(:response) { instance_double(RemoteResource::Response) }
61
-
62
- before do
63
- allow_any_instance_of(dummy_class).to receive(:handle_response)
64
- allow_any_instance_of(RemoteResource::Request).to receive(:perform) { response }
73
+ let(:response_body) do
74
+ {}
65
75
  end
66
76
 
67
- it 'instantiates the resource without attributes' do
68
- expect(dummy_class).to receive(:new).with(no_args()).and_call_original
69
- dummy_class.destroy('15')
77
+ let!(:expected_request) do
78
+ mock_request = stub_request(:delete, 'https://www.example.com/posts/12.json')
79
+ mock_request.to_return(status: 204, body: response_body.to_json)
80
+ mock_request
70
81
  end
71
82
 
72
- it 'performs a RemoteResource::Request' do
73
- expect(RemoteResource::Request).to receive(:new).with(dummy_class, :delete, { id: '15' }, { no_attributes: true }).and_call_original
74
- expect_any_instance_of(RemoteResource::Request).to receive(:perform)
75
- dummy_class.destroy('15')
83
+ it 'performs the HTTP request' do
84
+ Post.destroy(12)
85
+ expect(expected_request).to have_been_requested
76
86
  end
77
87
 
78
- it 'handles the RemoteResource::Response' do
79
- expect_any_instance_of(dummy_class).to receive(:handle_response).with response
80
- dummy_class.destroy('15')
88
+ it 'builds the correct non-persistent resource' do
89
+ post = Post.destroy(12)
90
+
91
+ aggregate_failures do
92
+ expect(post.id).to eql 12
93
+ expect(post.persisted?).to eql false
94
+ end
81
95
  end
82
96
 
83
97
  it 'does NOT change the given connection_options' do
84
98
  connection_options = { headers: { 'Foo' => 'Bar' } }
85
99
 
86
- expect { dummy_class.destroy('15', connection_options) }.not_to change { connection_options }.from({ headers: { 'Foo' => 'Bar' } })
100
+ expect { Post.destroy(12, connection_options) }.not_to change { connection_options }.from(connection_options.dup)
87
101
  end
88
102
 
89
- context 'request' do
90
- let(:response) { { status: 200, body: '' } }
91
- before { allow_any_instance_of(RemoteResource::Request).to receive(:perform).and_call_original }
92
-
93
- it 'generates correct request url' do
94
- stub_request(:delete, 'https://foobar.com/persistence_methods_dummy/15.json').with(body: nil).to_return(response)
95
- dummy_class.destroy('15')
96
- end
97
-
98
- it 'includes params' do
99
- stub_request(:delete, 'https://foobar.com/persistence_methods_dummy/15.json?pseudonym=3s8e3j').with(body: nil).to_return(response)
100
- dummy_class.destroy('15', params: { pseudonym: '3s8e3j' })
101
- end
103
+ xcontext 'return value #success? and NOT #success?' do
102
104
  end
103
105
  end
104
106
 
105
107
  describe '#update_attributes' do
106
- let(:dummy) { dummy_class.new id: 10 }
107
-
108
- let(:attributes) do
109
- { name: 'Noot' }
110
- end
111
-
112
- before do
113
- allow(dummy).to receive(:create_or_update) { dummy }
114
- allow(dummy).to receive(:success?)
115
- end
116
-
117
- it 'rebuilds the resource with the attributes' do
118
- expect(dummy).to receive(:rebuild_resource).with(attributes).and_call_original
119
- dummy.update_attributes attributes
120
- end
121
-
122
- context 'when the id is given in the attributes' do
123
- let(:attributes) do
124
- { id: 14, name: 'Noot' }
108
+ let(:response_body) do
109
+ {
110
+ data: {
111
+ id: 12,
112
+ title: 'Aliquam lobortis',
113
+ body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
114
+ featured: true,
115
+ created_at: Time.new(2015, 10, 4, 9, 30, 0),
116
+ }
117
+ }
118
+ end
119
+
120
+ context 'when resource is persisted' do
121
+ let(:resource) { Post.new(id: 12, title: 'Lorem Ipsum', body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', featured: true, created_at: Time.new(2015, 10, 4, 9, 30, 0)) }
122
+
123
+ let!(:expected_request) do
124
+ mock_request = stub_request(:patch, 'https://www.example.com/posts/12.json')
125
+ mock_request.to_return(status: 201, body: JSON.generate(response_body))
126
+ mock_request
125
127
  end
126
128
 
127
- it 'calls #create_or_update with the attributes and given id' do
128
- expect(dummy).to receive(:create_or_update).with(attributes, {})
129
- dummy.update_attributes attributes
129
+ it 'performs the HTTP request' do
130
+ resource.update_attributes(title: 'Aliquam lobortis', featured: true)
131
+ expect(expected_request).to have_been_requested
130
132
  end
131
133
 
132
- it 'does NOT change the given attributes' do
133
- expect { dummy.update_attributes(attributes) }.not_to change { attributes }.from({ id: 14, name: 'Noot' })
134
- end
134
+ it 'builds the correct resource' do
135
+ resource.update_attributes(title: 'Aliquam lobortis', featured: true)
135
136
 
136
- it 'does NOT change the given connection_options' do
137
- connection_options = { headers: { 'Foo' => 'Bar' } }
138
-
139
- expect { dummy.update_attributes(attributes, connection_options) }.not_to change { connection_options }.from({ headers: { 'Foo' => 'Bar' } })
140
- end
141
- end
137
+ post = resource
142
138
 
143
- context 'when the id is NOT given in the attributes' do
144
- it 'calls #create_or_update with the attributes and #id of resource' do
145
- expect(dummy).to receive(:create_or_update).with(attributes.merge(id: dummy.id), {})
146
- dummy.update_attributes attributes
139
+ aggregate_failures do
140
+ expect(post.persisted?).to eql true
141
+ expect(post.id).to eql 12
142
+ expect(post.title).to eql 'Aliquam lobortis'
143
+ expect(post.body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
144
+ expect(post.featured).to eql true
145
+ expect(post.created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
146
+ end
147
147
  end
148
148
 
149
149
  it 'does NOT change the given attributes' do
150
- expect { dummy.update_attributes(attributes) }.not_to change { attributes }.from({ name: 'Noot' })
150
+ attributes = { title: 'Aliquam lobortis', featured: true }
151
+
152
+ expect { resource.update_attributes(attributes) }.not_to change { attributes }.from(attributes.dup)
151
153
  end
152
154
 
153
155
  it 'does NOT change the given connection_options' do
156
+ attributes = { title: 'Aliquam lobortis', featured: true }
154
157
  connection_options = { headers: { 'Foo' => 'Bar' } }
155
158
 
156
- expect { dummy.update_attributes(attributes, connection_options) }.not_to change { connection_options }.from({ headers: { 'Foo' => 'Bar' } })
159
+ expect { resource.update_attributes(attributes, connection_options) }.not_to change { connection_options }.from(connection_options.dup)
157
160
  end
158
- end
159
-
160
- context 'when the save was successful' do
161
- it 'returns the resource' do
162
- allow(dummy).to receive(:success?) { true }
163
161
 
164
- expect(dummy.update_attributes attributes).to eql dummy
162
+ xcontext 'return value #success? and NOT #success?' do
165
163
  end
166
164
  end
167
165
 
168
- context 'when the save was NOT successful' do
169
- it 'returns false' do
170
- allow(dummy).to receive(:success?) { false }
166
+ context 'when resource is NOT persisted' do
167
+ let(:resource) { Post.new(title: 'Lorem Ipsum', body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', featured: true) }
171
168
 
172
- expect(dummy.update_attributes attributes).to eql false
169
+ let!(:expected_request) do
170
+ mock_request = stub_request(:post, 'https://www.example.com/posts.json')
171
+ mock_request.to_return(status: 201, body: JSON.generate(response_body))
172
+ mock_request
173
173
  end
174
- end
175
- end
176
174
 
177
- describe '#save' do
178
- let(:attributes) { dummy.attributes }
175
+ it 'performs the HTTP request' do
176
+ resource.update_attributes(title: 'Aliquam lobortis', featured: true)
177
+ expect(expected_request).to have_been_requested
178
+ end
179
179
 
180
- before do
181
- allow(dummy).to receive(:create_or_update) { dummy }
182
- allow(dummy).to receive(:success?)
183
- end
180
+ it 'builds the correct resource' do
181
+ resource.update_attributes(title: 'Aliquam lobortis', featured: true)
184
182
 
185
- it 'calls #create_or_update with the attributes' do
186
- expect(dummy).to receive(:create_or_update).with(attributes, {})
187
- dummy.save
188
- end
183
+ post = resource
189
184
 
190
- it 'does NOT change the given connection_options' do
191
- connection_options = { headers: { 'Foo' => 'Bar' } }
192
-
193
- expect { dummy.save(connection_options) }.not_to change { connection_options }.from({ headers: { 'Foo' => 'Bar' } })
194
- end
185
+ aggregate_failures do
186
+ expect(post.persisted?).to eql true
187
+ expect(post.id).to eql 12
188
+ expect(post.title).to eql 'Aliquam lobortis'
189
+ expect(post.body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
190
+ expect(post.featured).to eql true
191
+ expect(post.created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
192
+ end
193
+ end
195
194
 
196
- context 'when the save was successful' do
197
- it 'returns the resource' do
198
- allow(dummy).to receive(:success?) { true }
195
+ it 'does NOT change the given attributes' do
196
+ attributes = { title: 'Aliquam lobortis', featured: true }
199
197
 
200
- expect(dummy.save).to eql dummy
198
+ expect { resource.update_attributes(attributes) }.not_to change { attributes }.from(attributes.dup)
201
199
  end
202
- end
203
200
 
204
- context 'when the save was NOT successful' do
205
- it 'returns false' do
206
- allow(dummy).to receive(:success?) { false }
201
+ it 'does NOT change the given connection_options' do
202
+ attributes = { title: 'Aliquam lobortis', featured: true }
203
+ connection_options = { headers: { 'Foo' => 'Bar' } }
207
204
 
208
- expect(dummy.save).to eql false
205
+ expect { resource.update_attributes(attributes, connection_options) }.not_to change { connection_options }.from(connection_options.dup)
209
206
  end
210
- end
211
- end
212
-
213
- describe '#create_or_update' do
214
- let(:response) { instance_double(RemoteResource::Response) }
215
207
 
216
- before do
217
- allow(dummy).to receive(:handle_response) { dummy }
218
- allow_any_instance_of(RemoteResource::Request).to receive(:perform) { response }
208
+ xcontext 'return value #success? and NOT #success?' do
209
+ end
219
210
  end
211
+ end
220
212
 
221
- context 'when the attributes contain an id' do
222
- let(:attributes) do
223
- { id: 10, name: 'Kees' }
213
+ describe '#save' do
214
+ let(:response_body) do
215
+ {
216
+ data: {
217
+ id: 12,
218
+ title: 'Lorem Ipsum',
219
+ body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
220
+ featured: false,
221
+ created_at: Time.new(2015, 10, 4, 9, 30, 0),
222
+ }
223
+ }
224
+ end
225
+
226
+ context 'when resource is persisted' do
227
+ let(:resource) { Post.new(id: 12, title: 'Lorem Ipsum', body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', featured: false, created_at: Time.new(2015, 10, 4, 9, 30, 0)) }
228
+
229
+ let!(:expected_request) do
230
+ mock_request = stub_request(:patch, 'https://www.example.com/posts/12.json')
231
+ mock_request.to_return(status: 200, body: JSON.generate(response_body))
232
+ mock_request
224
233
  end
225
234
 
226
- it 'performs a RemoteResource::Request with rest_action :patch' do
227
- expect(RemoteResource::Request).to receive(:new).with(dummy, :patch, attributes, {}).and_call_original
228
- expect_any_instance_of(RemoteResource::Request).to receive(:perform)
229
- dummy.create_or_update attributes
235
+ it 'performs the HTTP request' do
236
+ resource.save
237
+ expect(expected_request).to have_been_requested
230
238
  end
231
239
 
232
- it 'handles the RemoteResource::Response' do
233
- expect(dummy).to receive(:handle_response).with response
234
- dummy.create_or_update attributes
235
- end
240
+ it 'builds the correct resource' do
241
+ resource.save
236
242
 
237
- it 'does NOT change the given attributes' do
238
- expect { dummy.create_or_update(attributes) }.not_to change { attributes }.from({ id: 10, name: 'Kees' })
243
+ post = resource
244
+
245
+ aggregate_failures do
246
+ expect(post.persisted?).to eql true
247
+ expect(post.id).to eql 12
248
+ expect(post.title).to eql 'Lorem Ipsum'
249
+ expect(post.body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
250
+ expect(post.featured).to eql false
251
+ expect(post.created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
252
+ end
239
253
  end
240
254
 
241
255
  it 'does NOT change the given connection_options' do
242
256
  connection_options = { headers: { 'Foo' => 'Bar' } }
243
257
 
244
- expect { dummy.create_or_update(attributes, connection_options) }.not_to change { connection_options }.from({ headers: { 'Foo' => 'Bar' } })
258
+ expect { resource.save(connection_options) }.not_to change { connection_options }.from(connection_options.dup)
245
259
  end
246
- end
247
260
 
248
- context 'when the attributes do NOT contain an id' do
249
- let(:attributes) do
250
- { name: 'Mies' }
261
+ xcontext 'return value #success? and NOT #success?' do
251
262
  end
263
+ end
252
264
 
253
- it 'performs a RemoteResource::Request with rest_action :post' do
254
- expect(RemoteResource::Request).to receive(:new).with(dummy, :post, attributes, {}).and_call_original
255
- expect_any_instance_of(RemoteResource::Request).to receive(:perform)
256
- dummy.create_or_update attributes
265
+ context 'when resource is NOT persisted' do
266
+ let(:resource) { Post.new(title: 'Lorem Ipsum', body: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', featured: false) }
267
+
268
+ let!(:expected_request) do
269
+ mock_request = stub_request(:post, 'https://www.example.com/posts.json')
270
+ mock_request.to_return(status: 201, body: JSON.generate(response_body))
271
+ mock_request
257
272
  end
258
273
 
259
- it 'handles the RemoteResource::Response' do
260
- expect(dummy).to receive(:handle_response).with response
261
- dummy.create_or_update attributes
274
+ it 'performs the HTTP request' do
275
+ resource.save
276
+ expect(expected_request).to have_been_requested
262
277
  end
263
278
 
264
- it 'does NOT change the given attributes' do
265
- expect { dummy.create_or_update(attributes) }.not_to change { attributes }.from({ name: 'Mies' })
279
+ it 'builds the correct resource' do
280
+ resource.save
281
+
282
+ post = resource
283
+
284
+ aggregate_failures do
285
+ expect(post.persisted?).to eql true
286
+ expect(post.id).to eql 12
287
+ expect(post.title).to eql 'Lorem Ipsum'
288
+ expect(post.body).to eql 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
289
+ expect(post.featured).to eql false
290
+ expect(post.created_at).to eql Time.new(2015, 10, 4, 9, 30, 0)
291
+ end
266
292
  end
267
293
 
268
294
  it 'does NOT change the given connection_options' do
269
295
  connection_options = { headers: { 'Foo' => 'Bar' } }
270
296
 
271
- expect { dummy.create_or_update(attributes, connection_options) }.not_to change { connection_options }.from({ headers: { 'Foo' => 'Bar' } })
297
+ expect { resource.save(connection_options) }.not_to change { connection_options }.from(connection_options.dup)
298
+ end
299
+
300
+ xcontext 'return value #success? and NOT #success?' do
272
301
  end
273
302
  end
274
303
  end
275
304
 
276
305
  describe '#destroy' do
277
- let(:dummy) { dummy_class.new(id: 18) }
306
+ let(:resource) { Post.new(id: 12) }
278
307
 
279
- let(:response) { instance_double(RemoteResource::Response) }
280
-
281
- before do
282
- allow(dummy).to receive(:handle_response) { dummy }
283
- allow_any_instance_of(RemoteResource::Request).to receive(:perform) { response }
284
- allow(dummy).to receive(:success?)
308
+ let(:response_body) do
309
+ {}
285
310
  end
286
311
 
287
- it 'performs a RemoteResource::Request with rest_action :delete' do
288
- expect(RemoteResource::Request).to receive(:new).with(dummy, :delete, { id: dummy.id }, { no_attributes: true }).and_call_original
289
- expect_any_instance_of(RemoteResource::Request).to receive(:perform)
290
- dummy.destroy
312
+ let!(:expected_request) do
313
+ mock_request = stub_request(:delete, 'https://www.example.com/posts/12.json')
314
+ mock_request.to_return(status: 204, body: response_body.to_json)
315
+ mock_request
291
316
  end
292
317
 
293
- it 'handles the RemoteResource::Response' do
294
- expect(dummy).to receive(:handle_response).with response
295
- dummy.destroy
318
+ it 'performs the HTTP request' do
319
+ resource.destroy
320
+ expect(expected_request).to have_been_requested
296
321
  end
297
322
 
298
- it 'does NOT change the given connection_options' do
299
- connection_options = { headers: { 'Foo' => 'Bar' } }
300
-
301
- expect { dummy.destroy(connection_options) }.not_to change { connection_options }.from({ headers: { 'Foo' => 'Bar' } })
302
- end
323
+ it 'builds the correct non-persistent resource' do
324
+ resource.destroy
303
325
 
304
- context 'request' do
305
- let(:response) { { status: 200, body: '' } }
306
- before { allow_any_instance_of(RemoteResource::Request).to receive(:perform).and_call_original }
307
-
308
- it 'generates correct request url' do
309
- stub_request(:delete, 'https://foobar.com/persistence_methods_dummy/18.json').with(body: nil).to_return(response)
310
- dummy.destroy
311
- end
326
+ post = resource
312
327
 
313
- it 'includes params' do
314
- stub_request(:delete, 'https://foobar.com/persistence_methods_dummy/18.json?pseudonym=3s8e3j').with(body: nil).to_return(response)
315
- dummy.destroy(params: { pseudonym: '3s8e3j' })
328
+ aggregate_failures do
329
+ expect(post.id).to eql 12
330
+ expect(post.persisted?).to eql false
316
331
  end
317
332
  end
318
333
 
319
- context 'when the destroy was successful' do
320
- it 'returns the resource' do
321
- allow(dummy).to receive(:success?) { true }
334
+ it 'does NOT change the given connection_options' do
335
+ connection_options = { headers: { 'Foo' => 'Bar' } }
322
336
 
323
- expect(dummy.destroy).to eql dummy
324
- end
337
+ expect { resource.destroy(connection_options) }.not_to change { connection_options }.from(connection_options.dup)
325
338
  end
326
339
 
327
- context 'when the destroy was NOT successful' do
328
- it 'returns false' do
329
- allow(dummy).to receive(:success?) { false }
330
-
331
- expect(dummy.destroy).to eql false
332
- end
340
+ xcontext 'return value #success? and NOT #success?' do
333
341
  end
334
342
 
335
343
  context 'when the id is NOT present' do
336
- let(:dummy) { dummy_class.new }
344
+ let(:resource) { Post.new }
337
345
 
338
346
  it 'raises the RemoteResource::IdMissingError error' do
339
- expect { dummy.destroy }.to raise_error(RemoteResource::IdMissingError, "`id` is missing from resource")
347
+ expect { resource.destroy }.to raise_error(RemoteResource::IdMissingError, "`id` is missing from resource")
340
348
  end
341
349
  end
342
350
  end