faraday 2.7.4 → 2.13.1
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/CHANGELOG.md +1 -1
- data/README.md +23 -11
- data/Rakefile +6 -1
- data/lib/faraday/adapter/test.rb +3 -3
- data/lib/faraday/adapter.rb +1 -1
- data/lib/faraday/connection.rb +27 -23
- data/lib/faraday/encoders/nested_params_encoder.rb +1 -1
- data/lib/faraday/error.rb +21 -3
- data/lib/faraday/logging/formatter.rb +13 -17
- data/lib/faraday/middleware.rb +40 -1
- data/lib/faraday/options/connection_options.rb +7 -6
- data/lib/faraday/options/env.rb +68 -69
- data/lib/faraday/options/proxy_options.rb +11 -5
- data/lib/faraday/options/request_options.rb +7 -6
- data/lib/faraday/options/ssl_options.rb +57 -50
- data/lib/faraday/options.rb +4 -3
- data/lib/faraday/rack_builder.rb +20 -20
- data/lib/faraday/request/instrumentation.rb +3 -1
- data/lib/faraday/request/json.rb +18 -3
- data/lib/faraday/request.rb +10 -7
- data/lib/faraday/response/json.rb +21 -1
- data/lib/faraday/response/logger.rb +5 -3
- data/lib/faraday/response/raise_error.rb +36 -17
- data/lib/faraday/utils/headers.rb +8 -2
- data/lib/faraday/utils.rb +3 -4
- data/lib/faraday/version.rb +1 -1
- data/spec/faraday/connection_spec.rb +2 -2
- data/spec/faraday/error_spec.rb +39 -6
- data/spec/faraday/middleware_spec.rb +143 -0
- data/spec/faraday/options/options_spec.rb +1 -1
- data/spec/faraday/options/proxy_options_spec.rb +35 -0
- data/spec/faraday/params_encoders/nested_spec.rb +2 -1
- data/spec/faraday/request/json_spec.rb +88 -0
- data/spec/faraday/response/json_spec.rb +89 -0
- data/spec/faraday/response/logger_spec.rb +49 -4
- data/spec/faraday/response/raise_error_spec.rb +104 -1
- data/spec/faraday/utils/headers_spec.rb +9 -0
- data/spec/faraday/utils_spec.rb +3 -1
- data/spec/faraday_spec.rb +10 -4
- data/spec/spec_helper.rb +6 -5
- data/spec/support/faraday_middleware_subclasses.rb +18 -0
- metadata +26 -14
data/spec/faraday/error_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
RSpec.describe Faraday::
|
3
|
+
RSpec.describe Faraday::Error do
|
4
4
|
describe '.initialize' do
|
5
5
|
subject { described_class.new(exception, response) }
|
6
6
|
let(:response) { nil }
|
@@ -12,8 +12,10 @@ RSpec.describe Faraday::ClientError do
|
|
12
12
|
it { expect(subject.response).to be_nil }
|
13
13
|
it { expect(subject.message).to eq(exception.message) }
|
14
14
|
it { expect(subject.backtrace).to eq(exception.backtrace) }
|
15
|
-
it { expect(subject.inspect).to eq('#<Faraday::
|
15
|
+
it { expect(subject.inspect).to eq('#<Faraday::Error wrapped=#<RuntimeError: test>>') }
|
16
16
|
it { expect(subject.response_status).to be_nil }
|
17
|
+
it { expect(subject.response_headers).to be_nil }
|
18
|
+
it { expect(subject.response_body).to be_nil }
|
17
19
|
end
|
18
20
|
|
19
21
|
context 'with response hash' do
|
@@ -22,8 +24,14 @@ RSpec.describe Faraday::ClientError do
|
|
22
24
|
it { expect(subject.wrapped_exception).to be_nil }
|
23
25
|
it { expect(subject.response).to eq(exception) }
|
24
26
|
it { expect(subject.message).to eq('the server responded with status 400') }
|
25
|
-
|
27
|
+
if RUBY_VERSION >= '3.4'
|
28
|
+
it { expect(subject.inspect).to eq('#<Faraday::Error response={status: 400}>') }
|
29
|
+
else
|
30
|
+
it { expect(subject.inspect).to eq('#<Faraday::Error response={:status=>400}>') }
|
31
|
+
end
|
26
32
|
it { expect(subject.response_status).to eq(400) }
|
33
|
+
it { expect(subject.response_headers).to be_nil }
|
34
|
+
it { expect(subject.response_body).to be_nil }
|
27
35
|
end
|
28
36
|
|
29
37
|
context 'with string' do
|
@@ -32,8 +40,10 @@ RSpec.describe Faraday::ClientError do
|
|
32
40
|
it { expect(subject.wrapped_exception).to be_nil }
|
33
41
|
it { expect(subject.response).to be_nil }
|
34
42
|
it { expect(subject.message).to eq('custom message') }
|
35
|
-
it { expect(subject.inspect).to eq('#<Faraday::
|
43
|
+
it { expect(subject.inspect).to eq('#<Faraday::Error #<Faraday::Error: custom message>>') }
|
36
44
|
it { expect(subject.response_status).to be_nil }
|
45
|
+
it { expect(subject.response_headers).to be_nil }
|
46
|
+
it { expect(subject.response_body).to be_nil }
|
37
47
|
end
|
38
48
|
|
39
49
|
context 'with anything else #to_s' do
|
@@ -42,8 +52,10 @@ RSpec.describe Faraday::ClientError do
|
|
42
52
|
it { expect(subject.wrapped_exception).to be_nil }
|
43
53
|
it { expect(subject.response).to be_nil }
|
44
54
|
it { expect(subject.message).to eq('["error1", "error2"]') }
|
45
|
-
it { expect(subject.inspect).to eq('#<Faraday::
|
55
|
+
it { expect(subject.inspect).to eq('#<Faraday::Error #<Faraday::Error: ["error1", "error2"]>>') }
|
46
56
|
it { expect(subject.response_status).to be_nil }
|
57
|
+
it { expect(subject.response_headers).to be_nil }
|
58
|
+
it { expect(subject.response_body).to be_nil }
|
47
59
|
end
|
48
60
|
|
49
61
|
context 'with exception string and response hash' do
|
@@ -53,8 +65,29 @@ RSpec.describe Faraday::ClientError do
|
|
53
65
|
it { expect(subject.wrapped_exception).to be_nil }
|
54
66
|
it { expect(subject.response).to eq(response) }
|
55
67
|
it { expect(subject.message).to eq('custom message') }
|
56
|
-
|
68
|
+
if RUBY_VERSION >= '3.4'
|
69
|
+
it { expect(subject.inspect).to eq('#<Faraday::Error response={status: 400}>') }
|
70
|
+
else
|
71
|
+
it { expect(subject.inspect).to eq('#<Faraday::Error response={:status=>400}>') }
|
72
|
+
end
|
57
73
|
it { expect(subject.response_status).to eq(400) }
|
74
|
+
it { expect(subject.response_headers).to be_nil }
|
75
|
+
it { expect(subject.response_body).to be_nil }
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'with exception and response object' do
|
79
|
+
let(:exception) { RuntimeError.new('test') }
|
80
|
+
let(:body) { { test: 'test' } }
|
81
|
+
let(:headers) { { 'Content-Type' => 'application/json' } }
|
82
|
+
let(:response) { Faraday::Response.new(status: 400, response_headers: headers, response_body: body) }
|
83
|
+
|
84
|
+
it { expect(subject.wrapped_exception).to eq(exception) }
|
85
|
+
it { expect(subject.response).to eq(response) }
|
86
|
+
it { expect(subject.message).to eq(exception.message) }
|
87
|
+
it { expect(subject.backtrace).to eq(exception.backtrace) }
|
88
|
+
it { expect(subject.response_status).to eq(400) }
|
89
|
+
it { expect(subject.response_headers).to eq(headers) }
|
90
|
+
it { expect(subject.response_body).to eq(body) }
|
58
91
|
end
|
59
92
|
end
|
60
93
|
end
|
@@ -67,4 +67,147 @@ RSpec.describe Faraday::Middleware do
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
70
|
+
|
71
|
+
describe '::default_options' do
|
72
|
+
let(:subclass_no_options) { FaradayMiddlewareSubclasses::SubclassNoOptions }
|
73
|
+
let(:subclass_one_option) { FaradayMiddlewareSubclasses::SubclassOneOption }
|
74
|
+
let(:subclass_two_options) { FaradayMiddlewareSubclasses::SubclassTwoOptions }
|
75
|
+
|
76
|
+
def build_conn(resp_middleware)
|
77
|
+
Faraday.new do |c|
|
78
|
+
c.adapter :test do |stub|
|
79
|
+
stub.get('/success') { [200, {}, 'ok'] }
|
80
|
+
end
|
81
|
+
c.response resp_middleware
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
RSpec.shared_context 'reset @default_options' do
|
86
|
+
before(:each) do
|
87
|
+
FaradayMiddlewareSubclasses::SubclassNoOptions.instance_variable_set(:@default_options, nil)
|
88
|
+
FaradayMiddlewareSubclasses::SubclassOneOption.instance_variable_set(:@default_options, nil)
|
89
|
+
FaradayMiddlewareSubclasses::SubclassTwoOptions.instance_variable_set(:@default_options, nil)
|
90
|
+
Faraday::Middleware.instance_variable_set(:@default_options, nil)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
after(:all) do
|
95
|
+
FaradayMiddlewareSubclasses::SubclassNoOptions.instance_variable_set(:@default_options, nil)
|
96
|
+
FaradayMiddlewareSubclasses::SubclassOneOption.instance_variable_set(:@default_options, nil)
|
97
|
+
FaradayMiddlewareSubclasses::SubclassTwoOptions.instance_variable_set(:@default_options, nil)
|
98
|
+
Faraday::Middleware.instance_variable_set(:@default_options, nil)
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'with subclass DEFAULT_OPTIONS defined' do
|
102
|
+
include_context 'reset @default_options'
|
103
|
+
|
104
|
+
context 'and without application options configured' do
|
105
|
+
let(:resp1) { build_conn(:one_option).get('/success') }
|
106
|
+
|
107
|
+
it 'has only subclass defaults' do
|
108
|
+
expect(Faraday::Middleware.default_options).to eq(Faraday::Middleware::DEFAULT_OPTIONS)
|
109
|
+
expect(subclass_no_options.default_options).to eq(subclass_no_options::DEFAULT_OPTIONS)
|
110
|
+
expect(subclass_one_option.default_options).to eq(subclass_one_option::DEFAULT_OPTIONS)
|
111
|
+
expect(subclass_two_options.default_options).to eq(subclass_two_options::DEFAULT_OPTIONS)
|
112
|
+
end
|
113
|
+
|
114
|
+
it { expect(resp1.body).to eq('ok') }
|
115
|
+
end
|
116
|
+
|
117
|
+
context "and with one application's options changed" do
|
118
|
+
let(:resp2) { build_conn(:two_options).get('/success') }
|
119
|
+
|
120
|
+
before(:each) do
|
121
|
+
FaradayMiddlewareSubclasses::SubclassTwoOptions.default_options = { some_option: false }
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'only updates default options of target subclass' do
|
125
|
+
expect(Faraday::Middleware.default_options).to eq(Faraday::Middleware::DEFAULT_OPTIONS)
|
126
|
+
expect(subclass_no_options.default_options).to eq(subclass_no_options::DEFAULT_OPTIONS)
|
127
|
+
expect(subclass_one_option.default_options).to eq(subclass_one_option::DEFAULT_OPTIONS)
|
128
|
+
expect(subclass_two_options.default_options).to eq({ some_option: false, some_other_option: false })
|
129
|
+
end
|
130
|
+
|
131
|
+
it { expect(resp2.body).to eq('ok') }
|
132
|
+
end
|
133
|
+
|
134
|
+
context "and with two applications' options changed" do
|
135
|
+
let(:resp1) { build_conn(:one_option).get('/success') }
|
136
|
+
let(:resp2) { build_conn(:two_options).get('/success') }
|
137
|
+
|
138
|
+
before(:each) do
|
139
|
+
FaradayMiddlewareSubclasses::SubclassOneOption.default_options = { some_other_option: true }
|
140
|
+
FaradayMiddlewareSubclasses::SubclassTwoOptions.default_options = { some_option: false }
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'updates subclasses and parent independent of each other' do
|
144
|
+
expect(Faraday::Middleware.default_options).to eq(Faraday::Middleware::DEFAULT_OPTIONS)
|
145
|
+
expect(subclass_no_options.default_options).to eq(subclass_no_options::DEFAULT_OPTIONS)
|
146
|
+
expect(subclass_one_option.default_options).to eq({ some_other_option: true })
|
147
|
+
expect(subclass_two_options.default_options).to eq({ some_option: false, some_other_option: false })
|
148
|
+
end
|
149
|
+
|
150
|
+
it { expect(resp1.body).to eq('ok') }
|
151
|
+
it { expect(resp2.body).to eq('ok') }
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'with FARADAY::MIDDLEWARE DEFAULT_OPTIONS and with Subclass DEFAULT_OPTIONS' do
|
156
|
+
before(:each) do
|
157
|
+
stub_const('Faraday::Middleware::DEFAULT_OPTIONS', { its_magic: false })
|
158
|
+
end
|
159
|
+
|
160
|
+
# Must stub Faraday::Middleware::DEFAULT_OPTIONS before resetting default options
|
161
|
+
include_context 'reset @default_options'
|
162
|
+
|
163
|
+
context 'and without application options configured' do
|
164
|
+
let(:resp1) { build_conn(:one_option).get('/success') }
|
165
|
+
|
166
|
+
it 'has only subclass defaults' do
|
167
|
+
expect(Faraday::Middleware.default_options).to eq(Faraday::Middleware::DEFAULT_OPTIONS)
|
168
|
+
expect(FaradayMiddlewareSubclasses::SubclassNoOptions.default_options).to eq({ its_magic: false })
|
169
|
+
expect(FaradayMiddlewareSubclasses::SubclassOneOption.default_options).to eq({ its_magic: false, some_other_option: false })
|
170
|
+
expect(FaradayMiddlewareSubclasses::SubclassTwoOptions.default_options).to eq({ its_magic: false, some_option: true, some_other_option: false })
|
171
|
+
end
|
172
|
+
|
173
|
+
it { expect(resp1.body).to eq('ok') }
|
174
|
+
end
|
175
|
+
|
176
|
+
context "and with two applications' options changed" do
|
177
|
+
let(:resp1) { build_conn(:one_option).get('/success') }
|
178
|
+
let(:resp2) { build_conn(:two_options).get('/success') }
|
179
|
+
|
180
|
+
before(:each) do
|
181
|
+
FaradayMiddlewareSubclasses::SubclassOneOption.default_options = { some_other_option: true }
|
182
|
+
FaradayMiddlewareSubclasses::SubclassTwoOptions.default_options = { some_option: false }
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'updates subclasses and parent independent of each other' do
|
186
|
+
expect(Faraday::Middleware.default_options).to eq(Faraday::Middleware::DEFAULT_OPTIONS)
|
187
|
+
expect(FaradayMiddlewareSubclasses::SubclassNoOptions.default_options).to eq({ its_magic: false })
|
188
|
+
expect(FaradayMiddlewareSubclasses::SubclassOneOption.default_options).to eq({ its_magic: false, some_other_option: true })
|
189
|
+
expect(FaradayMiddlewareSubclasses::SubclassTwoOptions.default_options).to eq({ its_magic: false, some_option: false, some_other_option: false })
|
190
|
+
end
|
191
|
+
|
192
|
+
it { expect(resp1.body).to eq('ok') }
|
193
|
+
it { expect(resp2.body).to eq('ok') }
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
describe 'default_options input validation' do
|
198
|
+
include_context 'reset @default_options'
|
199
|
+
|
200
|
+
it 'raises error if Faraday::Middleware option does not exist' do
|
201
|
+
expect { Faraday::Middleware.default_options = { something_special: true } }.to raise_error(Faraday::InitializationError) do |e|
|
202
|
+
expect(e.message).to eq('Invalid options provided. Keys not found in Faraday::Middleware::DEFAULT_OPTIONS: something_special')
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'raises error if subclass option does not exist' do
|
207
|
+
expect { subclass_one_option.default_options = { this_is_a_typo: true } }.to raise_error(Faraday::InitializationError) do |e|
|
208
|
+
expect(e.message).to eq('Invalid options provided. Keys not found in FaradayMiddlewareSubclasses::SubclassOneOption::DEFAULT_OPTIONS: this_is_a_typo')
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
70
213
|
end
|
@@ -27,11 +27,46 @@ RSpec.describe Faraday::ProxyOptions do
|
|
27
27
|
expect(options.inspect).to eq('#<Faraday::ProxyOptions (empty)>')
|
28
28
|
end
|
29
29
|
|
30
|
+
it 'works with hash' do
|
31
|
+
hash = { user: 'user', password: 'pass', uri: 'http://@example.org' }
|
32
|
+
options = Faraday::ProxyOptions.from(hash)
|
33
|
+
expect(options.user).to eq('user')
|
34
|
+
expect(options.password).to eq('pass')
|
35
|
+
expect(options.uri).to be_a_kind_of(URI)
|
36
|
+
expect(options.path).to eq('')
|
37
|
+
expect(options.port).to eq(80)
|
38
|
+
expect(options.host).to eq('example.org')
|
39
|
+
expect(options.scheme).to eq('http')
|
40
|
+
expect(options.inspect).to match('#<Faraday::ProxyOptions uri=')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'works with option' do
|
44
|
+
opt_arg = { user: 'user', password: 'pass', uri: 'http://@example.org' }
|
45
|
+
option = Faraday::ConnectionOptions.from(proxy: opt_arg)
|
46
|
+
options = Faraday::ProxyOptions.from(option.proxy)
|
47
|
+
expect(options.user).to eq('user')
|
48
|
+
expect(options.password).to eq('pass')
|
49
|
+
expect(options.uri).to be_a_kind_of(URI)
|
50
|
+
expect(options.path).to eq('')
|
51
|
+
expect(options.port).to eq(80)
|
52
|
+
expect(options.host).to eq('example.org')
|
53
|
+
expect(options.scheme).to eq('http')
|
54
|
+
expect(options.inspect).to match('#<Faraday::ProxyOptions uri=')
|
55
|
+
end
|
56
|
+
|
30
57
|
it 'works with no auth' do
|
31
58
|
proxy = Faraday::ProxyOptions.from 'http://example.org'
|
32
59
|
expect(proxy.user).to be_nil
|
33
60
|
expect(proxy.password).to be_nil
|
34
61
|
end
|
62
|
+
|
63
|
+
it 'treats empty string as nil' do
|
64
|
+
proxy = nil
|
65
|
+
proxy_string = proxy.to_s # => empty string
|
66
|
+
options = Faraday::ProxyOptions.from proxy_string
|
67
|
+
expect(options).to be_a_kind_of(Faraday::ProxyOptions)
|
68
|
+
expect(options.inspect).to eq('#<Faraday::ProxyOptions (empty)>')
|
69
|
+
end
|
35
70
|
end
|
36
71
|
|
37
72
|
it 'allows hash access' do
|
@@ -62,7 +62,8 @@ RSpec.describe Faraday::NestedParamsEncoder do
|
|
62
62
|
it 'encodes rack compat' do
|
63
63
|
params = { a: [{ one: '1', two: '2' }, '3', ''] }
|
64
64
|
result = Faraday::Utils.unescape(Faraday::NestedParamsEncoder.encode(params)).split('&')
|
65
|
-
|
65
|
+
escaped = Rack::Utils.build_nested_query(params)
|
66
|
+
expected = Rack::Utils.unescape(escaped).split('&')
|
66
67
|
expect(result).to match_array(expected)
|
67
68
|
end
|
68
69
|
|
@@ -73,6 +73,30 @@ RSpec.describe Faraday::Request::Json do
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
+
context 'true body' do
|
77
|
+
let(:result) { process(true) }
|
78
|
+
|
79
|
+
it 'encodes body' do
|
80
|
+
expect(result_body).to eq('true')
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'adds content type' do
|
84
|
+
expect(result_type).to eq('application/json')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'false body' do
|
89
|
+
let(:result) { process(false) }
|
90
|
+
|
91
|
+
it 'encodes body' do
|
92
|
+
expect(result_body).to eq('false')
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'adds content type' do
|
96
|
+
expect(result_type).to eq('application/json')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
76
100
|
context 'object body with json type' do
|
77
101
|
let(:result) { process({ a: 1 }, 'application/json; charset=utf-8') }
|
78
102
|
|
@@ -108,4 +132,68 @@ RSpec.describe Faraday::Request::Json do
|
|
108
132
|
expect(result_type).to eq('application/xml; charset=utf-8')
|
109
133
|
end
|
110
134
|
end
|
135
|
+
|
136
|
+
context 'with encoder' do
|
137
|
+
let(:encoder) do
|
138
|
+
double('Encoder').tap do |e|
|
139
|
+
allow(e).to receive(:dump) { |s, opts| JSON.generate(s, opts) }
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
let(:result) { process(a: 1) }
|
144
|
+
|
145
|
+
context 'when encoder is passed as object' do
|
146
|
+
let(:middleware) { described_class.new(->(env) { Faraday::Response.new(env) }, { encoder: encoder }) }
|
147
|
+
|
148
|
+
it 'calls specified JSON encoder\'s dump method' do
|
149
|
+
expect(encoder).to receive(:dump).with({ a: 1 })
|
150
|
+
|
151
|
+
result
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'encodes body' do
|
155
|
+
expect(result_body).to eq('{"a":1}')
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'adds content type' do
|
159
|
+
expect(result_type).to eq('application/json')
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'when encoder is passed as an object-method pair' do
|
164
|
+
let(:middleware) { described_class.new(->(env) { Faraday::Response.new(env) }, { encoder: [encoder, :dump] }) }
|
165
|
+
|
166
|
+
it 'calls specified JSON encoder' do
|
167
|
+
expect(encoder).to receive(:dump).with({ a: 1 })
|
168
|
+
|
169
|
+
result
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'encodes body' do
|
173
|
+
expect(result_body).to eq('{"a":1}')
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'adds content type' do
|
177
|
+
expect(result_type).to eq('application/json')
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context 'when encoder is not passed' do
|
182
|
+
let(:middleware) { described_class.new(->(env) { Faraday::Response.new(env) }) }
|
183
|
+
|
184
|
+
it 'calls JSON.generate' do
|
185
|
+
expect(JSON).to receive(:generate).with({ a: 1 })
|
186
|
+
|
187
|
+
result
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'encodes body' do
|
191
|
+
expect(result_body).to eq('{"a":1}')
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'adds content type' do
|
195
|
+
expect(result_type).to eq('application/json')
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
111
199
|
end
|
@@ -114,4 +114,93 @@ RSpec.describe Faraday::Response::Json, type: :response do
|
|
114
114
|
expect(response.body).to eq(result)
|
115
115
|
end
|
116
116
|
end
|
117
|
+
|
118
|
+
context 'with decoder' do
|
119
|
+
let(:decoder) do
|
120
|
+
double('Decoder').tap do |e|
|
121
|
+
allow(e).to receive(:load) { |s, opts| JSON.parse(s, opts) }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
let(:body) { '{"a": 1}' }
|
126
|
+
let(:result) { { a: 1 } }
|
127
|
+
|
128
|
+
context 'when decoder is passed as object' do
|
129
|
+
let(:options) do
|
130
|
+
{
|
131
|
+
parser_options: {
|
132
|
+
decoder: decoder,
|
133
|
+
option: :option_value,
|
134
|
+
symbolize_names: true
|
135
|
+
}
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'passes relevant options to specified decoder\'s load method' do
|
140
|
+
expect(decoder).to receive(:load)
|
141
|
+
.with(body, { option: :option_value, symbolize_names: true })
|
142
|
+
.and_return(result)
|
143
|
+
|
144
|
+
response = process(body)
|
145
|
+
expect(response.body).to eq(result)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'when decoder is passed as an object-method pair' do
|
150
|
+
let(:options) do
|
151
|
+
{
|
152
|
+
parser_options: {
|
153
|
+
decoder: [decoder, :load],
|
154
|
+
option: :option_value,
|
155
|
+
symbolize_names: true
|
156
|
+
}
|
157
|
+
}
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'passes relevant options to specified decoder\'s method' do
|
161
|
+
expect(decoder).to receive(:load)
|
162
|
+
.with(body, { option: :option_value, symbolize_names: true })
|
163
|
+
.and_return(result)
|
164
|
+
|
165
|
+
response = process(body)
|
166
|
+
expect(response.body).to eq(result)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'when decoder is not passed' do
|
171
|
+
let(:options) do
|
172
|
+
{
|
173
|
+
parser_options: {
|
174
|
+
symbolize_names: true
|
175
|
+
}
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'passes relevant options to JSON parse' do
|
180
|
+
expect(JSON).to receive(:parse)
|
181
|
+
.with(body, { symbolize_names: true })
|
182
|
+
.and_return(result)
|
183
|
+
|
184
|
+
response = process(body)
|
185
|
+
expect(response.body).to eq(result)
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'passes relevant options to JSON parse even when nil responds to :load' do
|
189
|
+
original_allow_message_expectations_on_nil = RSpec::Mocks.configuration.allow_message_expectations_on_nil
|
190
|
+
RSpec::Mocks.configuration.allow_message_expectations_on_nil = true
|
191
|
+
allow(nil).to receive(:respond_to?)
|
192
|
+
.with(:load)
|
193
|
+
.and_return(true)
|
194
|
+
|
195
|
+
expect(JSON).to receive(:parse)
|
196
|
+
.with(body, { symbolize_names: true })
|
197
|
+
.and_return(result)
|
198
|
+
|
199
|
+
response = process(body)
|
200
|
+
expect(response.body).to eq(result)
|
201
|
+
ensure
|
202
|
+
RSpec::Mocks.configuration.allow_message_expectations_on_nil = original_allow_message_expectations_on_nil
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
117
206
|
end
|
@@ -25,6 +25,7 @@ RSpec.describe Faraday::Response::Logger do
|
|
25
25
|
stubs.get('/filtered_headers') { [200, { 'Content-Type' => 'text/html' }, 'headers response'] }
|
26
26
|
stubs.get('/filtered_params') { [200, { 'Content-Type' => 'text/html' }, 'params response'] }
|
27
27
|
stubs.get('/filtered_url') { [200, { 'Content-Type' => 'text/html' }, 'url response'] }
|
28
|
+
stubs.get('/connection_failed') { raise Faraday::ConnectionFailed, 'Failed to open TCP connection' }
|
28
29
|
end
|
29
30
|
end
|
30
31
|
end
|
@@ -54,6 +55,26 @@ RSpec.describe Faraday::Response::Logger do
|
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
58
|
+
context 'when logger with program name' do
|
59
|
+
let(:logger) { Logger.new(string_io, progname: 'my_best_program') }
|
60
|
+
|
61
|
+
it 'logs with program name' do
|
62
|
+
conn.get '/hello'
|
63
|
+
|
64
|
+
expect(string_io.string).to match('-- my_best_program: request:')
|
65
|
+
expect(string_io.string).to match('-- my_best_program: response:')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when logger without program name' do
|
70
|
+
it 'logs without program name' do
|
71
|
+
conn.get '/hello'
|
72
|
+
|
73
|
+
expect(string_io.string).to match('-- : request:')
|
74
|
+
expect(string_io.string).to match('-- : response:')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
57
78
|
context 'with default formatter' do
|
58
79
|
let(:formatter) { instance_double(Faraday::Logging::Formatter, request: true, response: true, filter: []) }
|
59
80
|
|
@@ -168,7 +189,7 @@ RSpec.describe Faraday::Response::Logger do
|
|
168
189
|
context 'when logging request body' do
|
169
190
|
let(:logger_options) { { bodies: { request: true } } }
|
170
191
|
|
171
|
-
it '
|
192
|
+
it 'logs only request body' do
|
172
193
|
conn.post '/ohyes', 'name=Tamago', accept: 'text/html'
|
173
194
|
expect(string_io.string).to match(%(name=Tamago))
|
174
195
|
expect(string_io.string).not_to match(%(pebbles))
|
@@ -178,7 +199,7 @@ RSpec.describe Faraday::Response::Logger do
|
|
178
199
|
context 'when logging response body' do
|
179
200
|
let(:logger_options) { { bodies: { response: true } } }
|
180
201
|
|
181
|
-
it '
|
202
|
+
it 'logs only response body' do
|
182
203
|
conn.post '/ohyes', 'name=Hamachi', accept: 'text/html'
|
183
204
|
expect(string_io.string).to match(%(pebbles))
|
184
205
|
expect(string_io.string).not_to match(%(name=Hamachi))
|
@@ -188,13 +209,13 @@ RSpec.describe Faraday::Response::Logger do
|
|
188
209
|
context 'when logging request and response bodies' do
|
189
210
|
let(:logger_options) { { bodies: true } }
|
190
211
|
|
191
|
-
it '
|
212
|
+
it 'logs request and response body' do
|
192
213
|
conn.post '/ohyes', 'name=Ebi', accept: 'text/html'
|
193
214
|
expect(string_io.string).to match(%(name=Ebi))
|
194
215
|
expect(string_io.string).to match(%(pebbles))
|
195
216
|
end
|
196
217
|
|
197
|
-
it '
|
218
|
+
it 'logs response body object' do
|
198
219
|
conn.get '/rubbles', nil, accept: 'text/html'
|
199
220
|
expect(string_io.string).to match(%([\"Barney\", \"Betty\", \"Bam Bam\"]\n))
|
200
221
|
end
|
@@ -207,6 +228,21 @@ RSpec.describe Faraday::Response::Logger do
|
|
207
228
|
end
|
208
229
|
end
|
209
230
|
|
231
|
+
context 'when bodies are logged by default' do
|
232
|
+
before do
|
233
|
+
described_class.default_options = { bodies: true }
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'logs response body' do
|
237
|
+
conn.post '/ohai'
|
238
|
+
expect(string_io.string).to match(%(fred))
|
239
|
+
end
|
240
|
+
|
241
|
+
after do
|
242
|
+
described_class.default_options = { bodies: false }
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
210
246
|
context 'when logging errors' do
|
211
247
|
let(:logger_options) { { errors: true } }
|
212
248
|
|
@@ -216,6 +252,15 @@ RSpec.describe Faraday::Response::Logger do
|
|
216
252
|
end
|
217
253
|
end
|
218
254
|
|
255
|
+
context 'when logging headers and errors' do
|
256
|
+
let(:logger_options) { { headers: true, errors: true } }
|
257
|
+
|
258
|
+
it 'logs error message' do
|
259
|
+
expect { conn.get '/connection_failed' }.to raise_error(Faraday::ConnectionFailed)
|
260
|
+
expect(string_io.string).to match(%(Failed to open TCP connection))
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
219
264
|
context 'when using log_level' do
|
220
265
|
let(:logger_options) { { bodies: true, log_level: :debug } }
|
221
266
|
|