restforce 4.2.1 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/unhandled-salesforce-error.md +17 -0
  3. data/.github/dependabot.yml +10 -0
  4. data/.github/funding.yml +1 -0
  5. data/.github/workflows/build.yml +23 -0
  6. data/.github/workflows/faraday.yml +27 -0
  7. data/.rubocop.yml +5 -4
  8. data/CHANGELOG.md +115 -0
  9. data/CONTRIBUTING.md +21 -1
  10. data/Dockerfile +31 -0
  11. data/Gemfile +15 -7
  12. data/README.md +102 -24
  13. data/UPGRADING.md +67 -0
  14. data/docker-compose.yml +7 -0
  15. data/lib/restforce/abstract_client.rb +1 -0
  16. data/lib/restforce/collection.rb +27 -4
  17. data/lib/restforce/concerns/api.rb +3 -2
  18. data/lib/restforce/concerns/base.rb +2 -2
  19. data/lib/restforce/concerns/caching.rb +7 -0
  20. data/lib/restforce/concerns/composite_api.rb +104 -0
  21. data/lib/restforce/concerns/connection.rb +1 -1
  22. data/lib/restforce/concerns/picklists.rb +2 -2
  23. data/lib/restforce/concerns/streaming.rb +1 -3
  24. data/lib/restforce/config.rb +14 -9
  25. data/lib/restforce/error_code.rb +650 -0
  26. data/lib/restforce/file_part.rb +32 -0
  27. data/lib/restforce/mash.rb +8 -3
  28. data/lib/restforce/middleware/authentication.rb +1 -0
  29. data/lib/restforce/middleware/caching.rb +140 -15
  30. data/lib/restforce/middleware/json_request.rb +90 -0
  31. data/lib/restforce/middleware/json_response.rb +85 -0
  32. data/lib/restforce/middleware/logger.rb +14 -9
  33. data/lib/restforce/middleware/raise_error.rb +13 -5
  34. data/lib/restforce/middleware.rb +2 -0
  35. data/lib/restforce/version.rb +1 -1
  36. data/lib/restforce.rb +15 -14
  37. data/restforce.gemspec +13 -21
  38. data/spec/fixtures/sobject/list_view_results_success_response.json +151 -0
  39. data/spec/integration/abstract_client_spec.rb +56 -35
  40. data/spec/integration/data/client_spec.rb +6 -2
  41. data/spec/spec_helper.rb +24 -1
  42. data/spec/support/client_integration.rb +7 -7
  43. data/spec/support/concerns.rb +1 -1
  44. data/spec/support/fixture_helpers.rb +1 -3
  45. data/spec/support/middleware.rb +1 -2
  46. data/spec/unit/collection_spec.rb +38 -2
  47. data/spec/unit/concerns/api_spec.rb +22 -15
  48. data/spec/unit/concerns/authentication_spec.rb +6 -6
  49. data/spec/unit/concerns/caching_spec.rb +26 -0
  50. data/spec/unit/concerns/composite_api_spec.rb +143 -0
  51. data/spec/unit/concerns/connection_spec.rb +2 -2
  52. data/spec/unit/concerns/streaming_spec.rb +4 -4
  53. data/spec/unit/config_spec.rb +2 -2
  54. data/spec/unit/error_code_spec.rb +61 -0
  55. data/spec/unit/mash_spec.rb +5 -0
  56. data/spec/unit/middleware/authentication/jwt_bearer_spec.rb +24 -8
  57. data/spec/unit/middleware/authentication/password_spec.rb +12 -4
  58. data/spec/unit/middleware/authentication/token_spec.rb +12 -4
  59. data/spec/unit/middleware/authentication_spec.rb +14 -8
  60. data/spec/unit/middleware/gzip_spec.rb +2 -2
  61. data/spec/unit/middleware/raise_error_spec.rb +29 -10
  62. data/spec/unit/signed_request_spec.rb +1 -1
  63. metadata +64 -187
  64. data/.circleci/config.yml +0 -56
  65. 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 Metrics/LineLength
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=\"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),
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 Metrics/LineLength
94
+ # rubocop:enable Layout/LineLength
95
95
 
96
96
  subject do
97
97
  client.create('Account', Name: 'Foobar',
98
- Blob: Restforce::UploadIO.new(
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
- subject do
121
- lambda do
122
- client.update!('Account', Id: '001D000000INjVe', Name: 'Foobar')
123
- end
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
- it {
127
- should raise_error(
128
- Faraday::ResourceNotFound,
129
- "#{error.first['errorCode']}: #{error.first['message']}"
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 be_false }
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 be_true }
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 be_true }
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 be_true }
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 be_true }
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 be_true }
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 be_false }
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 be_true }
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
- "&client_secret=client_secret&username=foo" \
360
- "&password=barsecurity_token"
361
- ).to_return(status: 200, body: fixture(:auth_success_response))
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
- "&client_secret=client_secret&username=foo&" \
412
- "password=barsecurity_token"
413
- ).to_return(status: 200, body: fixture(:auth_success_response))
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
- body: fixture('expired_session_response'),
429
- headers: { 'Content-Type' => 'application/json' }).then.
445
+ body: fixture('expired_session_response'),
446
+ headers: { 'Content-Type' => 'application/json' }).then.
430
447
  to_return(status: 200,
431
- body: fixture('sobject/query_success_response'),
432
- headers: { 'Content-Type' => 'application/json' })
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
- "client_secret&username=foo&password=barsecurity_token"
437
- ).to_return(status: 200, body: fixture(:auth_success_response))
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
- client.faye.should_receive(:subscribe).with(['/topic/PushTopic'])
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
- client.faye.should_receive(:subscribe).with(['/topic/PushTopic1',
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")].each { |f| require f }
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
- 'E3Ds1eQz3z8jr3W7_VbWmEu4Q8TVGSTHxs'
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
- example_group: {
44
- describes: lambda do |described|
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)
@@ -15,6 +15,6 @@ module ConcernsExampleGroup
15
15
  end
16
16
 
17
17
  RSpec.configure do |config|
18
- config.include self, example_group: { file_path: %r{spec/unit/concerns} }
18
+ config.include self, file_path: %r{spec/unit/concerns}
19
19
  end
20
20
  end
@@ -22,9 +22,7 @@ module FixtureHelpers
22
22
  end
23
23
 
24
24
  def stub_login_request(*)
25
- stub = stub_request(:post, "https://login.salesforce.com/services/oauth2/token")
26
-
27
- stub
25
+ stub_request(:post, "https://login.salesforce.com/services/oauth2/token")
28
26
  end
29
27
 
30
28
  def fixture(filename)
@@ -19,8 +19,7 @@ module MiddlewareExampleGroup
19
19
  end
20
20
 
21
21
  RSpec.configure do |config|
22
- config.include self,
23
- example_group: { file_path: %r{spec/unit/middleware} }
22
+ config.include self, file_path: %r{spec/unit/middleware}
24
23
  end
25
24
  end
26
25
 
@@ -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 be_false }
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 be_true }
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(*args).
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(*args).
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
- with('sobjects/Whizbang/1234', StageName: "Call Scheduled")
317
- expect(result).to be_true
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
- with('sobjects/Whizbang/1234%2F%3Fabc', StageName: "Call Scheduled")
327
- expect(result).to be_true
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 be_true
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 be_true
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 be_true
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 be_true
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 be_true
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 be_true
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 be_true }
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 be_true }
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 be_true }
106
+ it { should be_truthy }
107
107
  end
108
108
 
109
109
  context 'when oauth options are not provided' do
110
- it { should_not be_true }
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 be_true }
131
+ it { should be_truthy }
132
132
  end
133
133
 
134
134
  context 'when jwt options are not provided' do
135
- it { should_not be_true }
135
+ it { should_not be true }
136
136
  end
137
137
  end
138
138
  end