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.
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
@@ -28,4 +28,30 @@ describe Restforce::Concerns::Caching do
28
28
  end
29
29
  end
30
30
  end
31
+
32
+ describe '.with_caching' do
33
+ let(:options) { double('Options') }
34
+
35
+ before do
36
+ client.stub options: options
37
+ end
38
+
39
+ it 'runs the block with caching enabled' do
40
+ options.should_receive(:[]=).with(:use_cache, true)
41
+ options.should_receive(:[]=).with(:use_cache, false)
42
+ expect { |b| client.with_caching(&b) }.to yield_control
43
+ end
44
+
45
+ context 'when an exception is raised' do
46
+ it 'ensures the :use_cache is set to false' do
47
+ options.should_receive(:[]=).with(:use_cache, true)
48
+ options.should_receive(:[]=).with(:use_cache, false)
49
+ expect {
50
+ client.with_caching do
51
+ raise 'Foo'
52
+ end
53
+ }.to raise_error 'Foo'
54
+ end
55
+ end
56
+ end
31
57
  end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Restforce::Concerns::CompositeAPI do
6
+ let(:endpoint) { 'composite' }
7
+
8
+ before do
9
+ client.should_receive(:options).and_return(api_version: 38.0)
10
+ end
11
+
12
+ shared_examples_for 'composite requests' do
13
+ it '#create' do
14
+ client.
15
+ should_receive(:api_post).
16
+ with(endpoint, { compositeRequest: [
17
+ {
18
+ method: 'POST',
19
+ url: '/services/data/v38.0/sobjects/Object',
20
+ body: { name: 'test' },
21
+ referenceId: 'create_ref'
22
+ }
23
+ ], allOrNone: all_or_none, collateSubrequests: false }.to_json).
24
+ and_return(response)
25
+
26
+ client.send(method) do |subrequests|
27
+ subrequests.create('Object', 'create_ref', name: 'test')
28
+ end
29
+ end
30
+
31
+ it '#update' do
32
+ client.
33
+ should_receive(:api_post).
34
+ with(endpoint, { compositeRequest: [
35
+ {
36
+ method: 'PATCH',
37
+ url: '/services/data/v38.0/sobjects/Object/123',
38
+ body: { name: 'test' },
39
+ referenceId: 'update_ref'
40
+ }
41
+ ], allOrNone: all_or_none, collateSubrequests: false }.to_json).
42
+ and_return(response)
43
+
44
+ client.send(method) do |subrequests|
45
+ subrequests.update('Object', 'update_ref', id: '123', name: 'test')
46
+ end
47
+ end
48
+
49
+ it '#destroy' do
50
+ client.
51
+ should_receive(:api_post).
52
+ with(endpoint, { compositeRequest: [
53
+ {
54
+ method: 'DELETE',
55
+ url: '/services/data/v38.0/sobjects/Object/123',
56
+ referenceId: 'destroy_ref'
57
+ }
58
+ ], allOrNone: all_or_none, collateSubrequests: false }.to_json).
59
+ and_return(response)
60
+
61
+ client.send(method) do |subrequests|
62
+ subrequests.destroy('Object', 'destroy_ref', '123')
63
+ end
64
+ end
65
+
66
+ it '#upsert' do
67
+ client.
68
+ should_receive(:api_post).
69
+ with(endpoint, { compositeRequest: [
70
+ {
71
+ method: 'PATCH',
72
+ url: '/services/data/v38.0/sobjects/Object/extIdField__c/456',
73
+ body: { name: 'test' },
74
+ referenceId: 'upsert_ref'
75
+ }
76
+ ], allOrNone: all_or_none, collateSubrequests: false }.to_json).
77
+ and_return(response)
78
+
79
+ client.send(method) do |subrequests|
80
+ subrequests.upsert('Object', 'upsert_ref', 'extIdField__c',
81
+ extIdField__c: '456', name: 'test')
82
+ end
83
+ end
84
+
85
+ it 'multiple subrequests' do
86
+ client.
87
+ should_receive(:api_post).
88
+ with(endpoint, { compositeRequest: [
89
+ {
90
+ method: 'POST',
91
+ url: '/services/data/v38.0/sobjects/Object',
92
+ body: { name: 'test' },
93
+ referenceId: 'create_ref'
94
+ },
95
+ {
96
+ method: 'PATCH',
97
+ url: '/services/data/v38.0/sobjects/Object/123',
98
+ body: { name: 'test' },
99
+ referenceId: 'update_ref'
100
+ },
101
+ {
102
+ method: 'DELETE',
103
+ url: '/services/data/v38.0/sobjects/Object/123',
104
+ referenceId: 'destroy_ref'
105
+ }
106
+ ], allOrNone: all_or_none, collateSubrequests: false }.to_json).
107
+ and_return(response)
108
+
109
+ client.send(method) do |subrequests|
110
+ subrequests.create('Object', 'create_ref', name: 'test')
111
+ subrequests.update('Object', 'update_ref', id: '123', name: 'test')
112
+ subrequests.destroy('Object', 'destroy_ref', '123')
113
+ end
114
+ end
115
+
116
+ it 'fails if more than 25 requests' do
117
+ expect do
118
+ client.send(method) do |subrequests|
119
+ 26.times do |i|
120
+ subrequests.upsert('Object', "upsert_ref_#{i}", 'extIdField__c',
121
+ extIdField__c: '456', name: 'test')
122
+ end
123
+ end
124
+ end.to raise_error(ArgumentError)
125
+ end
126
+ end
127
+
128
+ describe '#composite' do
129
+ let(:method) { :composite }
130
+ let(:all_or_none) { false }
131
+ let(:response) { double('Faraday::Response', body: { 'compositeResponse' => [] }) }
132
+ it_behaves_like 'composite requests'
133
+ end
134
+
135
+ describe '#composite!' do
136
+ let(:method) { :composite! }
137
+ let(:all_or_none) { true }
138
+ let(:response) do
139
+ double('Faraday::Response', body: { 'compositeResponse' => [] })
140
+ end
141
+ it_behaves_like 'composite requests'
142
+ end
143
+ end
@@ -73,9 +73,9 @@ describe Restforce::Concerns::Connection do
73
73
  Restforce.stub(log?: true)
74
74
  end
75
75
 
76
- it "must always be used last before the Faraday Adapter" do
76
+ it "must always be used as the last handler before the adapter" do
77
77
  client.middleware.handlers.reverse.index(Restforce::Middleware::Logger).
78
- should eq 1
78
+ should eq 0
79
79
  end
80
80
  end
81
81
  end
@@ -13,10 +13,10 @@ describe Restforce::Concerns::Streaming, event_machine: true do
13
13
  it 'subscribes to the topics with faye' do
14
14
  faye_double.
15
15
  should_receive(:subscribe).
16
- with(channels, &subscribe_block)
16
+ with(channels)
17
17
  client.stub faye: faye_double
18
18
 
19
- client.subscription(channels, &subscribe_block)
19
+ client.subscription(channels)
20
20
  end
21
21
 
22
22
  context "replay_handlers" do
@@ -87,7 +87,7 @@ describe Restforce::Concerns::Streaming, event_machine: true do
87
87
  end
88
88
 
89
89
  it 'connects to the streaming api' do
90
- client.stub authenticate!: OpenStruct.new(access_token: 'secret2')
90
+ client.stub authenticate!: double(access_token: 'secret2')
91
91
  faye_double = double('Faye::Client')
92
92
  Faye::Client.
93
93
  should_receive(:new).
@@ -110,7 +110,7 @@ describe Restforce::Concerns::Streaming, event_machine: true do
110
110
  end
111
111
  end
112
112
 
113
- describe Restforce::Concerns::Streaming::ReplayExtension do
113
+ describe "ReplayExtension" do
114
114
  let(:handlers) { {} }
115
115
  let(:extension) { Restforce::Concerns::Streaming::ReplayExtension.new(handlers) }
116
116
 
@@ -44,7 +44,7 @@ describe Restforce do
44
44
  'SALESFORCE_PROXY_URI' => 'proxy',
45
45
  'SALESFORCE_HOST' => 'test.host.com',
46
46
  'SALESFORCE_API_VERSION' => '37.0' }.
47
- each { |var, value| ENV.stub(:[]).with(var).and_return(value) }
47
+ each { |var, value| ENV.stub(:fetch).with(var, anything).and_return(value) }
48
48
  end
49
49
 
50
50
  its(:username) { should eq 'foo' }
@@ -76,7 +76,7 @@ describe Restforce do
76
76
  subject { Restforce.log? }
77
77
 
78
78
  context 'by default' do
79
- it { should be_false }
79
+ it { should be false }
80
80
  end
81
81
  end
82
82
 
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Restforce::ErrorCode do
6
+ describe "mapping of error codes to classes" do
7
+ subject(:error_exception_classes) { described_class::ERROR_EXCEPTION_CLASSES }
8
+
9
+ let(:exception_classes) do
10
+ described_class.constants.
11
+ map { |constant_name| described_class.const_get(constant_name) }.
12
+ select { |constant| constant.is_a?(Class) }
13
+ end
14
+
15
+ it "maps all defined exception classes to an error code" do
16
+ exception_classes.each do |exception_class|
17
+ expect(error_exception_classes.values).to include(exception_class)
18
+ end
19
+ end
20
+
21
+ it "maps all error codes to a defined exception class" do
22
+ error_exception_classes.each_value do |mapped_exception_class|
23
+ expect(exception_classes).to include(mapped_exception_class)
24
+ end
25
+ end
26
+ end
27
+
28
+ describe '.get_exception_class' do
29
+ context 'when a non-existent error code is looked up' do
30
+ let(:new_error_code) { 'ANOTHER_NEW_ERROR_CODE' }
31
+ subject { described_class.get_exception_class(new_error_code) }
32
+
33
+ it { should be Restforce::ResponseError }
34
+
35
+ it 'outputs a warning' do
36
+ expect(Warning).to receive(:warn)
37
+ subject
38
+ end
39
+ end
40
+
41
+ context 'when a known error code is looked up' do
42
+ let(:existing_error_code) { "ALL_OR_NONE_OPERATION_ROLLED_BACK" }
43
+ let(:existing_error) { described_class::AllOrNoneOperationRolledBack }
44
+
45
+ subject do
46
+ described_class.get_exception_class(existing_error_code)
47
+ end
48
+
49
+ it { should < Restforce::ResponseError }
50
+
51
+ it 'returns existing error' do
52
+ should be(existing_error)
53
+ end
54
+
55
+ it 'does not output a warning' do
56
+ expect(Warning).to_not receive(:warn)
57
+ subject
58
+ end
59
+ end
60
+ end
61
+ end
@@ -33,6 +33,11 @@ describe Restforce::Mash do
33
33
  let(:input) { { 'attributes' => { 'type' => 'Document' } } }
34
34
  it { should eq Restforce::Document }
35
35
  end
36
+
37
+ context 'when the attributes value is nil' do
38
+ let(:input) { { 'attributes' => nil } }
39
+ it { should eq Restforce::SObject }
40
+ end
36
41
  end
37
42
 
38
43
  context 'else' do
@@ -17,15 +17,23 @@ describe Restforce::Middleware::Authentication::JWTBearer do
17
17
  let(:success_request) do
18
18
  stub_login_request(
19
19
  body: "grant_type=grant_type—urn:ietf:params:oauth:grant-type:jwt-bearer&" \
20
- "assertion=abc1234567890"
21
- ).to_return(status: 200, body: fixture(:auth_success_response))
20
+ "assertion=abc1234567890"
21
+ ).to_return(
22
+ status: 200,
23
+ body: fixture(:auth_success_response),
24
+ headers: { "Content-Type" => "application/json" }
25
+ )
22
26
  end
23
27
 
24
28
  let(:fail_request) do
25
29
  stub_login_request(
26
30
  body: "grant_type=grant_type—urn:ietf:params:oauth:grant-type:jwt-bearer&" \
27
- "assertion=abc1234567890"
28
- ).to_return(status: 400, body: fixture(:refresh_error_response))
31
+ "assertion=abc1234567890"
32
+ ).to_return(
33
+ status: 400,
34
+ body: fixture(:refresh_error_response),
35
+ headers: { "Content-Type" => "application/json" }
36
+ )
29
37
  end
30
38
  end
31
39
 
@@ -47,15 +55,23 @@ describe Restforce::Middleware::Authentication::JWTBearer do
47
55
  let(:success_request) do
48
56
  stub_login_request(
49
57
  body: "grant_type=grant_type—urn:ietf:params:oauth:grant-type:jwt-bearer&" \
50
- "assertion=abc1234567890"
51
- ).to_return(status: 200, body: fixture(:auth_success_response))
58
+ "assertion=abc1234567890"
59
+ ).to_return(
60
+ status: 200,
61
+ body: fixture(:auth_success_response),
62
+ headers: { "Content-Type" => "application/json" }
63
+ )
52
64
  end
53
65
 
54
66
  let(:fail_request) do
55
67
  stub_login_request(
56
68
  body: "grant_type=grant_type—urn:ietf:params:oauth:grant-type:jwt-bearer&" \
57
- "assertion=abc1234567890"
58
- ).to_return(status: 400, body: fixture(:refresh_error_response))
69
+ "assertion=abc1234567890"
70
+ ).to_return(
71
+ status: 400,
72
+ body: fixture(:refresh_error_response),
73
+ headers: { "Content-Type" => "application/json" }
74
+ )
59
75
  end
60
76
  end
61
77
  end
@@ -17,15 +17,23 @@ describe Restforce::Middleware::Authentication::Password do
17
17
  let(:success_request) do
18
18
  stub_login_request(
19
19
  body: "grant_type=password&client_id=client_id&client_secret=client_secret" \
20
- "&username=foo&password=barsecurity_token"
21
- ).to_return(status: 200, body: fixture(:auth_success_response))
20
+ "&username=foo&password=barsecurity_token"
21
+ ).to_return(
22
+ status: 200,
23
+ body: fixture(:auth_success_response),
24
+ headers: { "Content-Type" => "application/json" }
25
+ )
22
26
  end
23
27
 
24
28
  let(:fail_request) do
25
29
  stub_login_request(
26
30
  body: "grant_type=password&client_id=client_id&client_secret=client_secret" \
27
- "&username=foo&password=barsecurity_token"
28
- ).to_return(status: 400, body: fixture(:auth_error_response))
31
+ "&username=foo&password=barsecurity_token"
32
+ ).to_return(
33
+ status: 400,
34
+ body: fixture(:auth_error_response),
35
+ headers: { "Content-Type" => "application/json" }
36
+ )
29
37
  end
30
38
  end
31
39
 
@@ -15,15 +15,23 @@ describe Restforce::Middleware::Authentication::Token do
15
15
  let(:success_request) do
16
16
  stub_login_request(
17
17
  body: "grant_type=refresh_token&refresh_token=refresh_token&" \
18
- "client_id=client_id&client_secret=client_secret"
19
- ).to_return(status: 200, body: fixture(:auth_success_response))
18
+ "client_id=client_id&client_secret=client_secret"
19
+ ).to_return(
20
+ status: 200,
21
+ body: fixture(:auth_success_response),
22
+ headers: { "Content-Type" => "application/json" }
23
+ )
20
24
  end
21
25
 
22
26
  let(:fail_request) do
23
27
  stub_login_request(
24
28
  body: "grant_type=refresh_token&refresh_token=refresh_token&" \
25
- "client_id=client_id&client_secret=client_secret"
26
- ).to_return(status: 400, body: fixture(:refresh_error_response))
29
+ "client_id=client_id&client_secret=client_secret"
30
+ ).to_return(
31
+ status: 400,
32
+ body: fixture(:refresh_error_response),
33
+ headers: { "Content-Type" => "application/json" }
34
+ )
27
35
  end
28
36
  end
29
37
  end
@@ -8,7 +8,9 @@ describe Restforce::Middleware::Authentication do
8
8
  proxy_uri: 'https://not-a-real-site.com',
9
9
  authentication_retries: retries,
10
10
  adapter: :net_http,
11
+ # rubocop:disable Naming/VariableNumber
11
12
  ssl: { version: :TLSv1_2 } }
13
+ # rubocop:enable Naming/VariableNumber
12
14
  end
13
15
 
14
16
  describe '.authenticate!' do
@@ -57,10 +59,10 @@ describe Restforce::Middleware::Authentication do
57
59
  end
58
60
 
59
61
  its(:handlers) {
60
- should include FaradayMiddleware::ParseJson,
61
- Faraday::Adapter::NetHttp
62
+ should include Restforce::Middleware::JsonResponse
62
63
  }
63
64
  its(:handlers) { should_not include Restforce::Middleware::Logger }
65
+ its(:adapter) { should eq Faraday::Adapter::NetHttp }
64
66
  end
65
67
 
66
68
  context 'with logging enabled' do
@@ -69,9 +71,10 @@ describe Restforce::Middleware::Authentication do
69
71
  end
70
72
 
71
73
  its(:handlers) {
72
- should include FaradayMiddleware::ParseJson,
73
- Restforce::Middleware::Logger, Faraday::Adapter::NetHttp
74
+ should include Restforce::Middleware::JsonResponse,
75
+ Restforce::Middleware::Logger
74
76
  }
77
+ its(:adapter) { should eq Faraday::Adapter::NetHttp }
75
78
  end
76
79
 
77
80
  context 'with specified adapter' do
@@ -80,21 +83,24 @@ describe Restforce::Middleware::Authentication do
80
83
  end
81
84
 
82
85
  its(:handlers) {
83
- should include FaradayMiddleware::ParseJson, Faraday::Adapter::Typhoeus
86
+ should include Restforce::Middleware::JsonResponse
84
87
  }
88
+ its(:adapter) { should eq Faraday::Adapter::Typhoeus }
85
89
  end
86
90
  end
87
91
 
88
92
  it "should have SSL config set" do
93
+ # rubocop:disable Naming/VariableNumber
89
94
  connection.ssl[:version].should eq(:TLSv1_2)
95
+ # rubocop:enable Naming/VariableNumber
90
96
  end
91
97
  end
92
98
 
93
99
  describe '.error_message' do
94
- context 'when response.body is present' do
100
+ context 'when response_body is present' do
95
101
  let(:response) {
96
102
  Faraday::Response.new(
97
- body: { 'error' => 'error', 'error_description' => 'description' },
103
+ response_body: { 'error' => 'error', 'error_description' => 'description' },
98
104
  status: 401
99
105
  )
100
106
  }
@@ -103,7 +109,7 @@ describe Restforce::Middleware::Authentication do
103
109
  it { should eq "error: description (401)" }
104
110
  end
105
111
 
106
- context 'when response.body is nil' do
112
+ context 'when response_body is nil' do
107
113
  let(:response) { Faraday::Response.new(status: 401) }
108
114
 
109
115
  subject { middleware.error_message(response) }
@@ -58,11 +58,11 @@ describe Restforce::Middleware::Gzip do
58
58
  env[:response_headers]['Content-Encoding'] = 'gzip'
59
59
  end
60
60
 
61
- it { should be_true }
61
+ it { should be true }
62
62
  end
63
63
 
64
64
  context 'when not gzipped' do
65
- it { should be_false }
65
+ it { should be false }
66
66
  end
67
67
  end
68
68
  end
@@ -14,8 +14,10 @@ describe Restforce::Middleware::RaiseError do
14
14
  let(:status) { 404 }
15
15
 
16
16
  it 'raises Restforce::NotFoundError' do
17
- expect { on_complete }.to raise_error Restforce::NotFoundError,
18
- 'INVALID_FIELD: error_message'
17
+ expect { on_complete }.to raise_error do |error|
18
+ expect(error).to be_a Restforce::NotFoundError
19
+ expect(error.message).to start_with("INVALID_FIELD: error_message")
20
+ end
19
21
  end
20
22
 
21
23
  it 'raises an error that inherits from Faraday::ResourceNotFound' do
@@ -40,8 +42,10 @@ describe Restforce::Middleware::RaiseError do
40
42
  let(:status) { 400 }
41
43
 
42
44
  it "raises an error derived from the response's errorCode" do
43
- expect { on_complete }.to raise_error Restforce::ErrorCode::InvalidField,
44
- 'INVALID_FIELD: error_message'
45
+ expect { on_complete }.to raise_error do |error|
46
+ expect(error).to be_a Restforce::ErrorCode::InvalidField
47
+ expect(error.message).to start_with("INVALID_FIELD: error_message")
48
+ end
45
49
  end
46
50
 
47
51
  it 'raises an error that inherits from Faraday::ClientError' do
@@ -53,8 +57,10 @@ describe Restforce::Middleware::RaiseError do
53
57
  let(:status) { 401 }
54
58
 
55
59
  it 'raises Restforce::UnauthorizedError' do
56
- expect { on_complete }.to raise_error Restforce::UnauthorizedError,
57
- 'INVALID_FIELD: error_message'
60
+ expect { on_complete }.to raise_error do |error|
61
+ expect(error).to be_a Restforce::UnauthorizedError
62
+ expect(error.message).to start_with("INVALID_FIELD: error_message")
63
+ end
58
64
  end
59
65
  end
60
66
 
@@ -76,13 +82,26 @@ describe Restforce::Middleware::RaiseError do
76
82
  let(:status) { 400 }
77
83
 
78
84
  it 'raises a generic Restforce::ResponseError' do
79
- expect { on_complete }.to raise_error Restforce::ResponseError,
80
- "(error code missing): #{body}"
85
+ expect { on_complete }.to raise_error do |error|
86
+ expect(error).to be_a Restforce::ResponseError
87
+ expect(error.message).to start_with("(error code missing): An error occured")
88
+ end
81
89
  end
82
90
 
83
91
  it 'raises an error that inherits from Faraday::ClientError' do
84
- expect { on_complete }.to raise_error Faraday::ClientError,
85
- "(error code missing): #{body}"
92
+ expect { on_complete }.to raise_error do |error|
93
+ expect(error).to be_a Faraday::ClientError
94
+ expect(error.message).to start_with("(error code missing): An error occured")
95
+ end
96
+ end
97
+ end
98
+
99
+ context 'when error code is not already defined' do
100
+ let(:body) { { 'errorCode' => 'SOMETHING_UNDEFINED' } }
101
+ let(:status) { 400 }
102
+
103
+ it 'raises a generic Restforce::ResponseError' do
104
+ expect { on_complete }.to raise_error Restforce::ResponseError
86
105
  end
87
106
  end
88
107
  end
@@ -6,7 +6,7 @@ describe Restforce::SignedRequest do
6
6
  let(:client_secret) { 'foo' }
7
7
  let(:digest) do
8
8
  if RUBY_VERSION < '2.1'
9
- OpenSSL::Digest::Digest.new('sha256')
9
+ OpenSSL::Digest.new('Digest', 'sha256')
10
10
  else
11
11
  OpenSSL::Digest.new('sha256')
12
12
  end