restforce 4.2.1 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/unhandled-salesforce-error.md +17 -0
- data/.github/dependabot.yml +10 -0
- data/.github/funding.yml +1 -0
- data/.github/workflows/build.yml +23 -0
- data/.github/workflows/faraday.yml +27 -0
- data/.rubocop.yml +5 -4
- data/CHANGELOG.md +115 -0
- data/CONTRIBUTING.md +21 -1
- data/Dockerfile +31 -0
- data/Gemfile +15 -7
- data/README.md +102 -24
- data/UPGRADING.md +67 -0
- data/docker-compose.yml +7 -0
- data/lib/restforce/abstract_client.rb +1 -0
- data/lib/restforce/collection.rb +27 -4
- data/lib/restforce/concerns/api.rb +3 -2
- data/lib/restforce/concerns/base.rb +2 -2
- data/lib/restforce/concerns/caching.rb +7 -0
- data/lib/restforce/concerns/composite_api.rb +104 -0
- data/lib/restforce/concerns/connection.rb +1 -1
- data/lib/restforce/concerns/picklists.rb +2 -2
- data/lib/restforce/concerns/streaming.rb +1 -3
- data/lib/restforce/config.rb +14 -9
- data/lib/restforce/error_code.rb +650 -0
- data/lib/restforce/file_part.rb +32 -0
- data/lib/restforce/mash.rb +8 -3
- data/lib/restforce/middleware/authentication.rb +1 -0
- data/lib/restforce/middleware/caching.rb +140 -15
- data/lib/restforce/middleware/json_request.rb +90 -0
- data/lib/restforce/middleware/json_response.rb +85 -0
- data/lib/restforce/middleware/logger.rb +14 -9
- data/lib/restforce/middleware/raise_error.rb +13 -5
- data/lib/restforce/middleware.rb +2 -0
- data/lib/restforce/version.rb +1 -1
- data/lib/restforce.rb +15 -14
- data/restforce.gemspec +13 -21
- data/spec/fixtures/sobject/list_view_results_success_response.json +151 -0
- data/spec/integration/abstract_client_spec.rb +56 -35
- data/spec/integration/data/client_spec.rb +6 -2
- data/spec/spec_helper.rb +24 -1
- data/spec/support/client_integration.rb +7 -7
- data/spec/support/concerns.rb +1 -1
- data/spec/support/fixture_helpers.rb +1 -3
- data/spec/support/middleware.rb +1 -2
- data/spec/unit/collection_spec.rb +38 -2
- data/spec/unit/concerns/api_spec.rb +22 -15
- data/spec/unit/concerns/authentication_spec.rb +6 -6
- data/spec/unit/concerns/caching_spec.rb +26 -0
- data/spec/unit/concerns/composite_api_spec.rb +143 -0
- data/spec/unit/concerns/connection_spec.rb +2 -2
- data/spec/unit/concerns/streaming_spec.rb +4 -4
- data/spec/unit/config_spec.rb +2 -2
- data/spec/unit/error_code_spec.rb +61 -0
- data/spec/unit/mash_spec.rb +5 -0
- data/spec/unit/middleware/authentication/jwt_bearer_spec.rb +24 -8
- data/spec/unit/middleware/authentication/password_spec.rb +12 -4
- data/spec/unit/middleware/authentication/token_spec.rb +12 -4
- data/spec/unit/middleware/authentication_spec.rb +14 -8
- data/spec/unit/middleware/gzip_spec.rb +2 -2
- data/spec/unit/middleware/raise_error_spec.rb +29 -10
- data/spec/unit/signed_request_spec.rb +1 -1
- metadata +64 -187
- data/.circleci/config.yml +0 -56
- data/lib/restforce/upload_io.rb +0 -9
@@ -0,0 +1,151 @@
|
|
1
|
+
{
|
2
|
+
"columns" : [ {
|
3
|
+
"ascendingLabel" : "Z-A",
|
4
|
+
"descendingLabel" : "A-Z",
|
5
|
+
"fieldNameOrPath" : "Name",
|
6
|
+
"hidden" : false,
|
7
|
+
"label" : "Account Name",
|
8
|
+
"selectListItem" : "Name",
|
9
|
+
"sortDirection" : "ascending",
|
10
|
+
"sortIndex" : 0,
|
11
|
+
"sortable" : true,
|
12
|
+
"type" : "string"
|
13
|
+
}, {
|
14
|
+
"ascendingLabel" : "Z-A",
|
15
|
+
"descendingLabel" : "A-Z",
|
16
|
+
"fieldNameOrPath" : "Site",
|
17
|
+
"hidden" : false,
|
18
|
+
"label" : "Account Site",
|
19
|
+
"selectListItem" : "Site",
|
20
|
+
"sortDirection" : null,
|
21
|
+
"sortIndex" : null,
|
22
|
+
"sortable" : true,
|
23
|
+
"type" : "string"
|
24
|
+
}, {
|
25
|
+
"ascendingLabel" : "Z-A",
|
26
|
+
"descendingLabel" : "A-Z",
|
27
|
+
"fieldNameOrPath" : "BillingState",
|
28
|
+
"hidden" : false,
|
29
|
+
"label" : "Billing State/Province",
|
30
|
+
"selectListItem" : "BillingState",
|
31
|
+
"sortDirection" : null,
|
32
|
+
"sortIndex" : null,
|
33
|
+
"sortable" : true,
|
34
|
+
"type" : "string"
|
35
|
+
}, {
|
36
|
+
"ascendingLabel" : "9-0",
|
37
|
+
"descendingLabel" : "0-9",
|
38
|
+
"fieldNameOrPath" : "Phone",
|
39
|
+
"hidden" : false,
|
40
|
+
"label" : "Phone",
|
41
|
+
"selectListItem" : "Phone",
|
42
|
+
"sortDirection" : null,
|
43
|
+
"sortIndex" : null,
|
44
|
+
"sortable" : true,
|
45
|
+
"type" : "phone"
|
46
|
+
}, {
|
47
|
+
"ascendingLabel" : "Low to High",
|
48
|
+
"descendingLabel" : "High to Low",
|
49
|
+
"fieldNameOrPath" : "Type",
|
50
|
+
"hidden" : false,
|
51
|
+
"label" : "Type",
|
52
|
+
"selectListItem" : "toLabel(Type)",
|
53
|
+
"sortDirection" : null,
|
54
|
+
"sortIndex" : null,
|
55
|
+
"sortable" : true,
|
56
|
+
"type" : "picklist"
|
57
|
+
}, {
|
58
|
+
"ascendingLabel" : "Z-A",
|
59
|
+
"descendingLabel" : "A-Z",
|
60
|
+
"fieldNameOrPath" : "Owner.Alias",
|
61
|
+
"hidden" : false,
|
62
|
+
"label" : "Account Owner Alias",
|
63
|
+
"selectListItem" : "Owner.Alias",
|
64
|
+
"sortDirection" : null,
|
65
|
+
"sortIndex" : null,
|
66
|
+
"sortable" : true,
|
67
|
+
"type" : "string"
|
68
|
+
}, {
|
69
|
+
"ascendingLabel" : null,
|
70
|
+
"descendingLabel" : null,
|
71
|
+
"fieldNameOrPath" : "Id",
|
72
|
+
"hidden" : true,
|
73
|
+
"label" : "Account ID",
|
74
|
+
"selectListItem" : "Id",
|
75
|
+
"sortDirection" : null,
|
76
|
+
"sortIndex" : null,
|
77
|
+
"sortable" : false,
|
78
|
+
"type" : "id"
|
79
|
+
}, {
|
80
|
+
"ascendingLabel" : null,
|
81
|
+
"descendingLabel" : null,
|
82
|
+
"fieldNameOrPath" : "CreatedDate",
|
83
|
+
"hidden" : true,
|
84
|
+
"label" : "Created Date",
|
85
|
+
"selectListItem" : "CreatedDate",
|
86
|
+
"sortDirection" : null,
|
87
|
+
"sortIndex" : null,
|
88
|
+
"sortable" : false,
|
89
|
+
"type" : "datetime"
|
90
|
+
}, {
|
91
|
+
"ascendingLabel" : null,
|
92
|
+
"descendingLabel" : null,
|
93
|
+
"fieldNameOrPath" : "LastModifiedDate",
|
94
|
+
"hidden" : true,
|
95
|
+
"label" : "Last Modified Date",
|
96
|
+
"selectListItem" : "LastModifiedDate",
|
97
|
+
"sortDirection" : null,
|
98
|
+
"sortIndex" : null,
|
99
|
+
"sortable" : false,
|
100
|
+
"type" : "datetime"
|
101
|
+
}, {
|
102
|
+
"ascendingLabel" : null,
|
103
|
+
"descendingLabel" : null,
|
104
|
+
"fieldNameOrPath" : "SystemModstamp",
|
105
|
+
"hidden" : true,
|
106
|
+
"label" : "System Modstamp",
|
107
|
+
"selectListItem" : "SystemModstamp",
|
108
|
+
"sortDirection" : null,
|
109
|
+
"sortIndex" : null,
|
110
|
+
"sortable" : false,
|
111
|
+
"type" : "datetime"
|
112
|
+
} ],
|
113
|
+
"developerName" : "MyAccounts",
|
114
|
+
"done" : true,
|
115
|
+
"id" : "00BD0000005WcCN",
|
116
|
+
"label" : "My Accounts",
|
117
|
+
"records" : [ {
|
118
|
+
"columns" : [ {
|
119
|
+
"fieldNameOrPath" : "Name",
|
120
|
+
"value" : "Burlington Textiles Corp of America"
|
121
|
+
}, {
|
122
|
+
"fieldNameOrPath" : "Site",
|
123
|
+
"value" : null
|
124
|
+
}, {
|
125
|
+
"fieldNameOrPath" : "BillingState",
|
126
|
+
"value" : "NC"
|
127
|
+
}, {
|
128
|
+
"fieldNameOrPath" : "Phone",
|
129
|
+
"value" : "(336) 222-7000"
|
130
|
+
}, {
|
131
|
+
"fieldNameOrPath" : "Type",
|
132
|
+
"value" : "Customer - Direct"
|
133
|
+
}, {
|
134
|
+
"fieldNameOrPath" : "Owner.Alias",
|
135
|
+
"value" : "TUser"
|
136
|
+
}, {
|
137
|
+
"fieldNameOrPath" : "Id",
|
138
|
+
"value" : "001D000000JliSTIAZ"
|
139
|
+
}, {
|
140
|
+
"fieldNameOrPath" : "CreatedDate",
|
141
|
+
"value" : "Fri Aug 01 21:15:46 GMT 2014"
|
142
|
+
}, {
|
143
|
+
"fieldNameOrPath" : "LastModifiedDate",
|
144
|
+
"value" : "Fri Aug 01 21:15:46 GMT 2014"
|
145
|
+
}, {
|
146
|
+
"fieldNameOrPath" : "SystemModstamp",
|
147
|
+
"value" : "Fri Aug 01 21:15:46 GMT 2014"
|
148
|
+
} ]
|
149
|
+
} ],
|
150
|
+
"size" : 1
|
151
|
+
}
|
@@ -86,22 +86,34 @@ shared_examples_for Restforce::AbstractClient do
|
|
86
86
|
end
|
87
87
|
|
88
88
|
context 'with multipart' do
|
89
|
-
# rubocop:disable
|
89
|
+
# rubocop:disable Layout/LineLength
|
90
90
|
requests 'sobjects/Account',
|
91
91
|
method: :post,
|
92
|
-
with_body: %r(----boundary_string\r\nContent-Disposition: form-data; name
|
92
|
+
with_body: %r(----boundary_string\r\nContent-Disposition: form-data; name="entity_content"\r\nContent-Type: application/json\r\n\r\n{"Name":"Foobar"}\r\n----boundary_string\r\nContent-Disposition: form-data; name="Blob"; filename="blob.jpg"\r\nContent-Length: 42171\r\nContent-Type: image/jpeg\r\nContent-Transfer-Encoding: binary),
|
93
93
|
fixture: 'sobject/create_success_response'
|
94
|
-
# rubocop:enable
|
94
|
+
# rubocop:enable Layout/LineLength
|
95
95
|
|
96
96
|
subject do
|
97
97
|
client.create('Account', Name: 'Foobar',
|
98
|
-
Blob: Restforce::
|
98
|
+
Blob: Restforce::FilePart.new(
|
99
99
|
File.expand_path('../fixtures/blob.jpg', __dir__),
|
100
100
|
'image/jpeg'
|
101
101
|
))
|
102
102
|
end
|
103
103
|
|
104
104
|
it { should eq 'some_id' }
|
105
|
+
|
106
|
+
context 'with deprecated UploadIO' do
|
107
|
+
subject do
|
108
|
+
client.create('Account', Name: 'Foobar',
|
109
|
+
Blob: Restforce::UploadIO.new(
|
110
|
+
File.expand_path('../fixtures/blob.jpg', __dir__),
|
111
|
+
'image/jpeg'
|
112
|
+
))
|
113
|
+
end
|
114
|
+
|
115
|
+
it { should eq 'some_id' }
|
116
|
+
end
|
105
117
|
end
|
106
118
|
end
|
107
119
|
|
@@ -117,18 +129,15 @@ shared_examples_for Restforce::AbstractClient do
|
|
117
129
|
JSON.parse(fixture('sobject/delete_error_response'))
|
118
130
|
end
|
119
131
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
end
|
132
|
+
it "raises Faraday::ResourceNotFound" do
|
133
|
+
expect { client.update!('Account', Id: '001D000000INjVe', Name: 'Foobar') }.
|
134
|
+
to raise_error do |exception|
|
135
|
+
expect(exception).to be_a(Faraday::ResourceNotFound)
|
125
136
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
)
|
131
|
-
}
|
137
|
+
expect(exception.message).
|
138
|
+
to start_with("#{error.first['errorCode']}: #{error.first['message']}")
|
139
|
+
end
|
140
|
+
end
|
132
141
|
end
|
133
142
|
end
|
134
143
|
|
@@ -146,7 +155,7 @@ shared_examples_for Restforce::AbstractClient do
|
|
146
155
|
fixture: 'sobject/delete_error_response'
|
147
156
|
|
148
157
|
subject { client.update('Account', Id: '001D000000INjVe', Name: 'Foobar') }
|
149
|
-
it { should
|
158
|
+
it { should be false }
|
150
159
|
end
|
151
160
|
|
152
161
|
context 'with success' do
|
@@ -160,7 +169,7 @@ shared_examples_for Restforce::AbstractClient do
|
|
160
169
|
client.update('Account', key => '001D000000INjVe', :Name => 'Foobar')
|
161
170
|
end
|
162
171
|
|
163
|
-
it { should
|
172
|
+
it { should be true }
|
164
173
|
end
|
165
174
|
end
|
166
175
|
end
|
@@ -179,7 +188,7 @@ shared_examples_for Restforce::AbstractClient do
|
|
179
188
|
Name: 'Foobar')
|
180
189
|
end
|
181
190
|
|
182
|
-
it { should
|
191
|
+
it { should be true }
|
183
192
|
end
|
184
193
|
|
185
194
|
context 'with string external Id key' do
|
@@ -188,7 +197,7 @@ shared_examples_for Restforce::AbstractClient do
|
|
188
197
|
'Name' => 'Foobar')
|
189
198
|
end
|
190
199
|
|
191
|
-
it { should
|
200
|
+
it { should be true }
|
192
201
|
end
|
193
202
|
end
|
194
203
|
|
@@ -245,14 +254,14 @@ shared_examples_for Restforce::AbstractClient do
|
|
245
254
|
context 'with success' do
|
246
255
|
requests 'sobjects/Account/001D000000INjVe', method: :delete
|
247
256
|
|
248
|
-
it { should
|
257
|
+
it { should be true }
|
249
258
|
end
|
250
259
|
|
251
260
|
context 'with a space in the id' do
|
252
261
|
subject(:destroy!) { client.destroy!('Account', '001D000000 INjVe') }
|
253
262
|
requests 'sobjects/Account/001D000000%20INjVe', method: :delete
|
254
263
|
|
255
|
-
it { should
|
264
|
+
it { should be true }
|
256
265
|
end
|
257
266
|
end
|
258
267
|
|
@@ -265,13 +274,13 @@ shared_examples_for Restforce::AbstractClient do
|
|
265
274
|
method: :delete,
|
266
275
|
status: 404
|
267
276
|
|
268
|
-
it { should
|
277
|
+
it { should be false }
|
269
278
|
end
|
270
279
|
|
271
280
|
context 'with success' do
|
272
281
|
requests 'sobjects/Account/001D000000INjVe', method: :delete
|
273
282
|
|
274
|
-
it { should
|
283
|
+
it { should be true }
|
275
284
|
end
|
276
285
|
end
|
277
286
|
|
@@ -356,9 +365,13 @@ shared_examples_for Restforce::AbstractClient do
|
|
356
365
|
before do
|
357
366
|
@request = stub_login_request(
|
358
367
|
with_body: "grant_type=password&client_id=client_id" \
|
359
|
-
|
360
|
-
|
361
|
-
).to_return(
|
368
|
+
"&client_secret=client_secret&username=foo" \
|
369
|
+
"&password=barsecurity_token"
|
370
|
+
).to_return(
|
371
|
+
status: 200,
|
372
|
+
body: fixture(:auth_success_response),
|
373
|
+
headers: { "Content-Type" => "application/json" }
|
374
|
+
)
|
362
375
|
end
|
363
376
|
|
364
377
|
after do
|
@@ -408,9 +421,13 @@ shared_examples_for Restforce::AbstractClient do
|
|
408
421
|
|
409
422
|
@query_request = stub_login_request(
|
410
423
|
with_body: "grant_type=password&client_id=client_id" \
|
411
|
-
|
412
|
-
|
413
|
-
).to_return(
|
424
|
+
"&client_secret=client_secret&username=foo&" \
|
425
|
+
"password=barsecurity_token"
|
426
|
+
).to_return(
|
427
|
+
status: 200,
|
428
|
+
body: fixture(:auth_success_response),
|
429
|
+
headers: { "Content-Type" => "application/json" }
|
430
|
+
)
|
414
431
|
end
|
415
432
|
|
416
433
|
subject { lambda { client.query('SELECT some, fields FROM object') } }
|
@@ -425,16 +442,20 @@ shared_examples_for Restforce::AbstractClient do
|
|
425
442
|
@query = stub_api_request('query\?q=SELECT%20some,%20fields%20FROM%20object').
|
426
443
|
with(headers: { 'Authorization' => "OAuth #{oauth_token}" }).
|
427
444
|
to_return(status: 401,
|
428
|
-
|
429
|
-
|
445
|
+
body: fixture('expired_session_response'),
|
446
|
+
headers: { 'Content-Type' => 'application/json' }).then.
|
430
447
|
to_return(status: 200,
|
431
|
-
|
432
|
-
|
448
|
+
body: fixture('sobject/query_success_response'),
|
449
|
+
headers: { 'Content-Type' => 'application/json' })
|
433
450
|
|
434
451
|
@login = stub_login_request(
|
435
452
|
with_body: "grant_type=password&client_id=client_id&client_secret=" \
|
436
|
-
|
437
|
-
).to_return(
|
453
|
+
"client_secret&username=foo&password=barsecurity_token"
|
454
|
+
).to_return(
|
455
|
+
status: 200,
|
456
|
+
body: fixture(:auth_success_response),
|
457
|
+
headers: { "Content-Type" => "application/json" }
|
458
|
+
)
|
438
459
|
end
|
439
460
|
|
440
461
|
after do
|
@@ -98,17 +98,21 @@ shared_examples_for Restforce::Data::Client do
|
|
98
98
|
end
|
99
99
|
|
100
100
|
describe '.subscribe', event_machine: true do
|
101
|
+
let(:faye_double) { double('Faye') }
|
102
|
+
|
101
103
|
context 'when given a single pushtopic' do
|
102
104
|
it 'subscribes to the pushtopic' do
|
103
|
-
|
105
|
+
faye_double.should_receive(:subscribe).with(['/topic/PushTopic'])
|
106
|
+
client.stub faye: faye_double
|
104
107
|
client.subscribe('PushTopic')
|
105
108
|
end
|
106
109
|
end
|
107
110
|
|
108
111
|
context 'when given an array of pushtopics' do
|
109
112
|
it 'subscribes to each pushtopic' do
|
110
|
-
|
113
|
+
faye_double.should_receive(:subscribe).with(['/topic/PushTopic1',
|
111
114
|
'/topic/PushTopic2'])
|
115
|
+
client.stub faye: faye_double
|
112
116
|
client.subscribe(%w[PushTopic1 PushTopic2])
|
113
117
|
end
|
114
118
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -8,6 +8,8 @@ Bundler.require :default, :test
|
|
8
8
|
require 'faye' unless RUBY_PLATFORM == 'java'
|
9
9
|
|
10
10
|
require 'webmock/rspec'
|
11
|
+
require 'rspec/collection_matchers'
|
12
|
+
require 'rspec/its'
|
11
13
|
|
12
14
|
WebMock.disable_net_connect!
|
13
15
|
|
@@ -15,8 +17,29 @@ RSpec.configure do |config|
|
|
15
17
|
config.order = 'random'
|
16
18
|
config.filter_run focus: true
|
17
19
|
config.run_all_when_everything_filtered = true
|
20
|
+
|
21
|
+
original_stderr = $stderr
|
22
|
+
original_stdout = $stdout
|
23
|
+
config.before(:all) do
|
24
|
+
# Redirect stderr and stdout
|
25
|
+
$stderr = File.open(File::NULL, "w")
|
26
|
+
$stdout = File.open(File::NULL, "w")
|
27
|
+
end
|
28
|
+
config.after(:all) do
|
29
|
+
$stderr = original_stderr
|
30
|
+
$stdout = original_stdout
|
31
|
+
end
|
32
|
+
|
33
|
+
config.expect_with :rspec do |expectations|
|
34
|
+
expectations.syntax = %i[expect should]
|
35
|
+
end
|
36
|
+
|
37
|
+
config.mock_with :rspec do |mocks|
|
38
|
+
mocks.syntax = %i[expect should]
|
39
|
+
end
|
18
40
|
end
|
19
41
|
|
20
42
|
# Requires supporting ruby files with custom matchers and macros, etc,
|
21
43
|
# in spec/support/ and its subdirectories.
|
22
|
-
Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")]
|
44
|
+
paths = Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")]
|
45
|
+
paths.sort.each { |f| require f }
|
@@ -5,7 +5,7 @@ module ClientIntegrationExampleGroup
|
|
5
5
|
base.class_eval do
|
6
6
|
let(:oauth_token) do
|
7
7
|
'00Dx0000000BV7z!AR8AQAxo9UfVkh8AlV0Gomt9Czx9LjHnSSpwBMmbRcgKFmxOtvxjTrKW19ye6P' \
|
8
|
-
|
8
|
+
'E3Ds1eQz3z8jr3W7_VbWmEu4Q8TVGSTHxs'
|
9
9
|
end
|
10
10
|
|
11
11
|
let(:refresh_token) { 'refresh' }
|
@@ -39,13 +39,13 @@ module ClientIntegrationExampleGroup
|
|
39
39
|
end
|
40
40
|
|
41
41
|
RSpec.configure do |config|
|
42
|
+
describes = lambda do |described|
|
43
|
+
described <= Restforce::AbstractClient
|
44
|
+
end
|
45
|
+
|
42
46
|
config.include self,
|
43
|
-
|
44
|
-
|
45
|
-
described <= Restforce::AbstractClient
|
46
|
-
end,
|
47
|
-
file_path: %r{spec/integration}
|
48
|
-
}
|
47
|
+
file_path: %r{spec/integration},
|
48
|
+
describes: describes
|
49
49
|
|
50
50
|
config.before mashify: false do
|
51
51
|
base_options.merge!(mashify: false)
|
data/spec/support/concerns.rb
CHANGED
@@ -22,9 +22,7 @@ module FixtureHelpers
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def stub_login_request(*)
|
25
|
-
|
26
|
-
|
27
|
-
stub
|
25
|
+
stub_request(:post, "https://login.salesforce.com/services/oauth2/token")
|
28
26
|
end
|
29
27
|
|
30
28
|
def fixture(filename)
|
data/spec/support/middleware.rb
CHANGED
@@ -13,7 +13,7 @@ describe Restforce::Collection do
|
|
13
13
|
|
14
14
|
it { should respond_to :each }
|
15
15
|
its(:size) { should eq 1 }
|
16
|
-
its(:has_next_page?) { should
|
16
|
+
its(:has_next_page?) { should be false }
|
17
17
|
it { should have_client client }
|
18
18
|
its(:page_size) { should eq 1 }
|
19
19
|
|
@@ -56,10 +56,46 @@ describe Restforce::Collection do
|
|
56
56
|
should(be_all { |page| expect(page).to be_a Restforce::Collection })
|
57
57
|
end
|
58
58
|
|
59
|
-
its(:has_next_page?) { should
|
59
|
+
its(:has_next_page?) { should be true }
|
60
60
|
it { should(be_all { |record| expect(record).to be_a Restforce::SObject }) }
|
61
61
|
its(:next_page) { should be_a Restforce::Collection }
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
65
|
+
|
66
|
+
describe '#size' do
|
67
|
+
subject(:size) do
|
68
|
+
described_class.new(JSON.parse(fixture(sobject_fixture)), client).size
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when the query response contains a totalSize field' do
|
72
|
+
let(:sobject_fixture) { 'sobject/query_success_response' }
|
73
|
+
|
74
|
+
it { should eq 1 }
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'when the query response contains a size field' do
|
78
|
+
let(:sobject_fixture) { 'sobject/list_view_results_success_response' }
|
79
|
+
|
80
|
+
it { should eq 1 }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#empty?' do
|
85
|
+
subject(:empty?) do
|
86
|
+
described_class.new(JSON.parse(fixture(sobject_fixture)), client).empty?
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'with size 1' do
|
90
|
+
let(:sobject_fixture) { 'sobject/query_success_response' }
|
91
|
+
|
92
|
+
it { should be false }
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'with size 0' do
|
96
|
+
let(:sobject_fixture) { 'sobject/query_empty_response' }
|
97
|
+
|
98
|
+
it { should be true }
|
99
|
+
end
|
100
|
+
end
|
65
101
|
end
|
@@ -11,7 +11,7 @@ describe Restforce::Concerns::API do
|
|
11
11
|
it 'returns the user info from identity url' do
|
12
12
|
identity_url = double('identity_url')
|
13
13
|
response.body.stub(:identity).and_return(identity_url)
|
14
|
-
client.should_receive(:api_get).with.and_return(response)
|
14
|
+
client.should_receive(:api_get).with(no_args).and_return(response)
|
15
15
|
|
16
16
|
identity = double('identity')
|
17
17
|
identity.stub(:body).and_return(identity)
|
@@ -268,7 +268,7 @@ describe Restforce::Concerns::API do
|
|
268
268
|
|
269
269
|
it "delegates to :#{method}!" do
|
270
270
|
client.should_receive(:"#{method}!").
|
271
|
-
with(
|
271
|
+
with(no_args).
|
272
272
|
and_return(response)
|
273
273
|
expect(result).to eq response
|
274
274
|
end
|
@@ -276,7 +276,7 @@ describe Restforce::Concerns::API do
|
|
276
276
|
it 'rescues exceptions' do
|
277
277
|
[Faraday::ClientError].each do |exception_klass|
|
278
278
|
client.should_receive(:"#{method}!").
|
279
|
-
with(
|
279
|
+
with(no_args).
|
280
280
|
and_raise(exception_klass.new(nil))
|
281
281
|
expect(result).to eq false
|
282
282
|
end
|
@@ -312,9 +312,12 @@ describe Restforce::Concerns::API do
|
|
312
312
|
let(:attrs) { { id: '1234', StageName: "Call Scheduled" } }
|
313
313
|
|
314
314
|
it 'sends an HTTP PATCH, and returns true' do
|
315
|
-
client.should_receive(:api_patch)
|
316
|
-
|
317
|
-
|
315
|
+
client.should_receive(:api_patch) do |*args|
|
316
|
+
expect(args).to eq(["sobjects/Whizbang/1234",
|
317
|
+
{ StageName: "Call Scheduled" }])
|
318
|
+
end
|
319
|
+
|
320
|
+
expect(result).to be true
|
318
321
|
end
|
319
322
|
end
|
320
323
|
|
@@ -322,9 +325,13 @@ describe Restforce::Concerns::API do
|
|
322
325
|
let(:attrs) { { id: '1234/?abc', StageName: "Call Scheduled" } }
|
323
326
|
|
324
327
|
it 'sends an HTTP PATCH, and encodes the ID' do
|
325
|
-
client.should_receive(:api_patch)
|
326
|
-
|
327
|
-
|
328
|
+
client.should_receive(:api_patch) do |*args|
|
329
|
+
expect(args).to eq(['sobjects/Whizbang/1234%2F%3Fabc', {
|
330
|
+
StageName: "Call Scheduled"
|
331
|
+
}])
|
332
|
+
end
|
333
|
+
|
334
|
+
expect(result).to be true
|
328
335
|
end
|
329
336
|
end
|
330
337
|
|
@@ -348,7 +355,7 @@ describe Restforce::Concerns::API do
|
|
348
355
|
client.should_receive(:api_patch).
|
349
356
|
with('sobjects/Whizbang/External_ID__c/1234', {}).
|
350
357
|
and_return(response)
|
351
|
-
expect(result).to
|
358
|
+
expect(result).to be true
|
352
359
|
end
|
353
360
|
|
354
361
|
context 'and the response body is a string' do
|
@@ -357,7 +364,7 @@ describe Restforce::Concerns::API do
|
|
357
364
|
client.should_receive(:api_patch).
|
358
365
|
with('sobjects/Whizbang/External_ID__c/1234', {}).
|
359
366
|
and_return(response)
|
360
|
-
expect(result).to
|
367
|
+
expect(result).to be true
|
361
368
|
end
|
362
369
|
end
|
363
370
|
end
|
@@ -431,7 +438,7 @@ describe Restforce::Concerns::API do
|
|
431
438
|
client.should_receive(:api_patch).
|
432
439
|
with('sobjects/Whizbang/External_ID__c/%E3%81%82', {}).
|
433
440
|
and_return(response)
|
434
|
-
expect(result).to
|
441
|
+
expect(result).to be true
|
435
442
|
end
|
436
443
|
end
|
437
444
|
end
|
@@ -448,7 +455,7 @@ describe Restforce::Concerns::API do
|
|
448
455
|
client.should_receive(:api_patch).
|
449
456
|
with('sobjects/Whizbang/External_ID__c/1234', {}).
|
450
457
|
and_return(response)
|
451
|
-
expect(result).to
|
458
|
+
expect(result).to be true
|
452
459
|
end
|
453
460
|
end
|
454
461
|
end
|
@@ -462,7 +469,7 @@ describe Restforce::Concerns::API do
|
|
462
469
|
it 'sends and HTTP delete, and returns true' do
|
463
470
|
client.should_receive(:api_delete).
|
464
471
|
with('sobjects/Whizbang/1234')
|
465
|
-
expect(result).to
|
472
|
+
expect(result).to be true
|
466
473
|
end
|
467
474
|
|
468
475
|
context 'when the id field contains special characters' do
|
@@ -471,7 +478,7 @@ describe Restforce::Concerns::API do
|
|
471
478
|
it 'sends an HTTP delete, and encodes the ID' do
|
472
479
|
client.should_receive(:api_delete).
|
473
480
|
with('sobjects/Whizbang/1234%2F%3Fabc')
|
474
|
-
expect(result).to
|
481
|
+
expect(result).to be true
|
475
482
|
end
|
476
483
|
end
|
477
484
|
end
|
@@ -80,11 +80,11 @@ describe Restforce::Concerns::Authentication do
|
|
80
80
|
client_secret: 'secret' }
|
81
81
|
end
|
82
82
|
|
83
|
-
it { should
|
83
|
+
it { should be_truthy }
|
84
84
|
end
|
85
85
|
|
86
86
|
context 'when username and password options are not provided' do
|
87
|
-
it { should_not
|
87
|
+
it { should_not be_truthy }
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
@@ -103,11 +103,11 @@ describe Restforce::Concerns::Authentication do
|
|
103
103
|
client_secret: 'secret' }
|
104
104
|
end
|
105
105
|
|
106
|
-
it { should
|
106
|
+
it { should be_truthy }
|
107
107
|
end
|
108
108
|
|
109
109
|
context 'when oauth options are not provided' do
|
110
|
-
it { should_not
|
110
|
+
it { should_not be true }
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
@@ -128,11 +128,11 @@ describe Restforce::Concerns::Authentication do
|
|
128
128
|
client_id: 'client' }
|
129
129
|
end
|
130
130
|
|
131
|
-
it { should
|
131
|
+
it { should be_truthy }
|
132
132
|
end
|
133
133
|
|
134
134
|
context 'when jwt options are not provided' do
|
135
|
-
it { should_not
|
135
|
+
it { should_not be true }
|
136
136
|
end
|
137
137
|
end
|
138
138
|
end
|