faraday 1.0.0 → 2.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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +221 -1
  3. data/LICENSE.md +1 -1
  4. data/README.md +19 -14
  5. data/examples/client_spec.rb +36 -4
  6. data/examples/client_test.rb +43 -4
  7. data/lib/faraday/adapter/test.rb +61 -43
  8. data/lib/faraday/adapter.rb +3 -16
  9. data/lib/faraday/adapter_registry.rb +3 -1
  10. data/lib/faraday/connection.rb +25 -78
  11. data/lib/faraday/encoders/flat_params_encoder.rb +9 -2
  12. data/lib/faraday/encoders/nested_params_encoder.rb +9 -4
  13. data/lib/faraday/error.rb +23 -8
  14. data/lib/faraday/logging/formatter.rb +1 -0
  15. data/lib/faraday/methods.rb +6 -0
  16. data/lib/faraday/middleware.rb +14 -5
  17. data/lib/faraday/middleware_registry.rb +15 -79
  18. data/lib/faraday/options/proxy_options.rb +4 -0
  19. data/lib/faraday/options.rb +7 -11
  20. data/lib/faraday/rack_builder.rb +34 -30
  21. data/lib/faraday/request/authorization.rb +32 -36
  22. data/lib/faraday/request/instrumentation.rb +2 -0
  23. data/lib/faraday/request/json.rb +55 -0
  24. data/lib/faraday/request/url_encoded.rb +5 -1
  25. data/lib/faraday/request.rb +13 -23
  26. data/lib/faraday/response/json.rb +54 -0
  27. data/lib/faraday/response/logger.rb +4 -4
  28. data/lib/faraday/response/raise_error.rb +20 -1
  29. data/lib/faraday/response.rb +8 -22
  30. data/lib/faraday/utils/headers.rb +3 -3
  31. data/lib/faraday/utils.rb +21 -8
  32. data/lib/faraday/version.rb +5 -0
  33. data/lib/faraday.rb +44 -59
  34. data/spec/faraday/adapter/test_spec.rb +377 -0
  35. data/spec/faraday/connection_spec.rb +147 -51
  36. data/spec/faraday/error_spec.rb +15 -0
  37. data/spec/faraday/middleware_spec.rb +32 -6
  38. data/spec/faraday/options/env_spec.rb +2 -2
  39. data/spec/faraday/options/proxy_options_spec.rb +7 -0
  40. data/spec/faraday/params_encoders/flat_spec.rb +8 -0
  41. data/spec/faraday/params_encoders/nested_spec.rb +8 -0
  42. data/spec/faraday/rack_builder_spec.rb +144 -38
  43. data/spec/faraday/request/authorization_spec.rb +19 -24
  44. data/spec/faraday/request/instrumentation_spec.rb +5 -7
  45. data/spec/faraday/request/json_spec.rb +111 -0
  46. data/spec/faraday/request/url_encoded_spec.rb +13 -1
  47. data/spec/faraday/request_spec.rb +6 -6
  48. data/spec/faraday/response/json_spec.rb +117 -0
  49. data/spec/faraday/response/raise_error_spec.rb +66 -0
  50. data/spec/faraday/utils_spec.rb +62 -1
  51. data/spec/support/fake_safe_buffer.rb +1 -1
  52. data/spec/support/helper_methods.rb +0 -37
  53. data/spec/support/shared_examples/adapter.rb +2 -2
  54. data/spec/support/shared_examples/request_method.rb +43 -28
  55. metadata +16 -48
  56. data/UPGRADING.md +0 -55
  57. data/lib/faraday/adapter/em_http.rb +0 -285
  58. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -62
  59. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -69
  60. data/lib/faraday/adapter/em_synchrony.rb +0 -150
  61. data/lib/faraday/adapter/excon.rb +0 -124
  62. data/lib/faraday/adapter/httpclient.rb +0 -151
  63. data/lib/faraday/adapter/net_http.rb +0 -209
  64. data/lib/faraday/adapter/net_http_persistent.rb +0 -91
  65. data/lib/faraday/adapter/patron.rb +0 -132
  66. data/lib/faraday/adapter/rack.rb +0 -75
  67. data/lib/faraday/adapter/typhoeus.rb +0 -15
  68. data/lib/faraday/autoload.rb +0 -95
  69. data/lib/faraday/dependency_loader.rb +0 -37
  70. data/lib/faraday/file_part.rb +0 -128
  71. data/lib/faraday/param_part.rb +0 -53
  72. data/lib/faraday/request/basic_authentication.rb +0 -20
  73. data/lib/faraday/request/multipart.rb +0 -99
  74. data/lib/faraday/request/retry.rb +0 -239
  75. data/lib/faraday/request/token_authentication.rb +0 -20
  76. data/spec/faraday/adapter/em_http_spec.rb +0 -47
  77. data/spec/faraday/adapter/em_synchrony_spec.rb +0 -16
  78. data/spec/faraday/adapter/excon_spec.rb +0 -49
  79. data/spec/faraday/adapter/httpclient_spec.rb +0 -73
  80. data/spec/faraday/adapter/net_http_persistent_spec.rb +0 -57
  81. data/spec/faraday/adapter/net_http_spec.rb +0 -64
  82. data/spec/faraday/adapter/patron_spec.rb +0 -18
  83. data/spec/faraday/adapter/rack_spec.rb +0 -8
  84. data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
  85. data/spec/faraday/composite_read_io_spec.rb +0 -80
  86. data/spec/faraday/request/multipart_spec.rb +0 -274
  87. data/spec/faraday/request/retry_spec.rb +0 -242
  88. data/spec/faraday/response/middleware_spec.rb +0 -52
  89. data/spec/support/webmock_rack_app.rb +0 -68
@@ -12,16 +12,16 @@ RSpec.describe Faraday::RackBuilder do
12
12
 
13
13
  class Apple < Handler
14
14
  end
15
+
15
16
  class Orange < Handler
16
17
  end
17
- class Banana < Handler
18
- end
19
18
 
20
- class Broken < Faraday::Middleware
21
- dependency 'zomg/i_dont/exist'
19
+ class Banana < Handler
22
20
  end
23
21
 
24
22
  subject { conn.builder }
23
+ before { Faraday.default_adapter = :test }
24
+ after { Faraday.default_adapter = nil }
25
25
 
26
26
  context 'with default stack' do
27
27
  let(:conn) { Faraday::Connection.new }
@@ -88,13 +88,6 @@ RSpec.describe Faraday::RackBuilder do
88
88
 
89
89
  it { expect(subject.handlers).to eq([Apple]) }
90
90
 
91
- it 'allows rebuilding' do
92
- subject.build do |builder|
93
- builder.use(Orange)
94
- end
95
- expect(subject.handlers).to eq([Orange])
96
- end
97
-
98
91
  it 'allows use' do
99
92
  subject.use(Orange)
100
93
  expect(subject.handlers).to eq([Apple, Orange])
@@ -127,24 +120,6 @@ RSpec.describe Faraday::RackBuilder do
127
120
  subject.use(:apple)
128
121
  expect(subject.handlers).to eq([Apple])
129
122
  end
130
-
131
- it 'allows to register with symbol' do
132
- Faraday::Middleware.register_middleware(apple: :Apple)
133
- subject.use(:apple)
134
- expect(subject.handlers).to eq([Apple])
135
- end
136
-
137
- it 'allows to register with string' do
138
- Faraday::Middleware.register_middleware(apple: 'Apple')
139
- subject.use(:apple)
140
- expect(subject.handlers).to eq([Apple])
141
- end
142
-
143
- it 'allows to register with Proc' do
144
- Faraday::Middleware.register_middleware(apple: -> { Apple })
145
- subject.use(:apple)
146
- expect(subject.handlers).to eq([Apple])
147
- end
148
123
  end
149
124
 
150
125
  context 'when having two handlers' do
@@ -176,21 +151,152 @@ RSpec.describe Faraday::RackBuilder do
176
151
  end
177
152
  end
178
153
 
179
- context 'when having a handler with broken dependency' do
180
- let(:conn) do
181
- Faraday::Connection.new do |builder|
182
- builder.adapter :test do |stub|
183
- stub.get('/') { |_| [200, {}, ''] }
154
+ context 'when middleware is added with named arguments' do
155
+ let(:conn) { Faraday::Connection.new {} }
156
+
157
+ let(:dog_middleware) do
158
+ Class.new(Faraday::Middleware) do
159
+ attr_accessor :name
160
+
161
+ def initialize(app, name:)
162
+ super(app)
163
+ @name = name
164
+ end
165
+ end
166
+ end
167
+ let(:dog) do
168
+ subject.handlers.find { |handler| handler == dog_middleware }.build
169
+ end
170
+
171
+ it 'adds a handler to construct middleware with options passed to use' do
172
+ subject.use dog_middleware, name: 'Rex'
173
+ expect { dog }.to_not output(
174
+ /warning: Using the last argument as keyword parameters is deprecated/
175
+ ).to_stderr
176
+ expect(dog.name).to eq('Rex')
177
+ end
178
+ end
179
+
180
+ context 'when a middleware is added with named arguments' do
181
+ let(:conn) { Faraday::Connection.new {} }
182
+
183
+ let(:cat_request) do
184
+ Class.new(Faraday::Middleware) do
185
+ attr_accessor :name
186
+
187
+ def initialize(app, name:)
188
+ super(app)
189
+ @name = name
184
190
  end
185
191
  end
186
192
  end
193
+ let(:cat) do
194
+ subject.handlers.find { |handler| handler == cat_request }.build
195
+ end
196
+
197
+ it 'adds a handler to construct request adapter with options passed to request' do
198
+ Faraday::Request.register_middleware cat_request: cat_request
199
+ subject.request :cat_request, name: 'Felix'
200
+ expect { cat }.to_not output(
201
+ /warning: Using the last argument as keyword parameters is deprecated/
202
+ ).to_stderr
203
+ expect(cat.name).to eq('Felix')
204
+ end
205
+ end
187
206
 
188
- before { subject.use(Broken) }
207
+ context 'when a middleware is added with named arguments' do
208
+ let(:conn) { Faraday::Connection.new {} }
209
+
210
+ let(:fish_response) do
211
+ Class.new(Faraday::Middleware) do
212
+ attr_accessor :name
189
213
 
190
- it 'raises an error while making a request' do
191
- expect { conn.get('/') }.to raise_error(RuntimeError) do |err|
192
- expect(err.message).to eq('missing dependency for Broken: cannot load such file -- zomg/i_dont/exist')
214
+ def initialize(app, name:)
215
+ super(app)
216
+ @name = name
217
+ end
218
+ end
219
+ end
220
+ let(:fish) do
221
+ subject.handlers.find { |handler| handler == fish_response }.build
222
+ end
223
+
224
+ it 'adds a handler to construct response adapter with options passed to response' do
225
+ Faraday::Response.register_middleware fish_response: fish_response
226
+ subject.response :fish_response, name: 'Bubbles'
227
+ expect { fish }.to_not output(
228
+ /warning: Using the last argument as keyword parameters is deprecated/
229
+ ).to_stderr
230
+ expect(fish.name).to eq('Bubbles')
231
+ end
232
+ end
233
+
234
+ context 'when a plain adapter is added with named arguments' do
235
+ let(:conn) { Faraday::Connection.new {} }
236
+
237
+ let(:rabbit_adapter) do
238
+ Class.new(Faraday::Adapter) do
239
+ attr_accessor :name
240
+
241
+ def initialize(app, name:)
242
+ super(app)
243
+ @name = name
244
+ end
193
245
  end
194
246
  end
247
+ let(:rabbit) do
248
+ subject.adapter.build
249
+ end
250
+
251
+ it 'adds a handler to construct adapter with options passed to adapter' do
252
+ Faraday::Adapter.register_middleware rabbit_adapter: rabbit_adapter
253
+ subject.adapter :rabbit_adapter, name: 'Thumper'
254
+ expect { rabbit }.to_not output(
255
+ /warning: Using the last argument as keyword parameters is deprecated/
256
+ ).to_stderr
257
+ expect(rabbit.name).to eq('Thumper')
258
+ end
259
+ end
260
+
261
+ context 'when handlers are directly added or updated' do
262
+ let(:conn) { Faraday::Connection.new {} }
263
+
264
+ let(:rock_handler) do
265
+ Class.new do
266
+ attr_accessor :name
267
+
268
+ def initialize(_app, name:)
269
+ @name = name
270
+ end
271
+ end
272
+ end
273
+ let(:rock) do
274
+ subject.handlers.find { |handler| handler == rock_handler }.build
275
+ end
276
+
277
+ it 'adds a handler to construct adapter with options passed to insert' do
278
+ subject.insert 0, rock_handler, name: 'Stony'
279
+ expect { rock }.to_not output(
280
+ /warning: Using the last argument as keyword parameters is deprecated/
281
+ ).to_stderr
282
+ expect(rock.name).to eq('Stony')
283
+ end
284
+
285
+ it 'adds a handler with options passed to insert_after' do
286
+ subject.insert_after 0, rock_handler, name: 'Rocky'
287
+ expect { rock }.to_not output(
288
+ /warning: Using the last argument as keyword parameters is deprecated/
289
+ ).to_stderr
290
+ expect(rock.name).to eq('Rocky')
291
+ end
292
+
293
+ it 'adds a handler with options passed to swap' do
294
+ subject.insert 0, rock_handler, name: 'Flint'
295
+ subject.swap 0, rock_handler, name: 'Chert'
296
+ expect { rock }.to_not output(
297
+ /warning: Using the last argument as keyword parameters is deprecated/
298
+ ).to_stderr
299
+ expect(rock.name).to eq('Chert')
300
+ end
195
301
  end
196
302
  end
@@ -3,7 +3,7 @@
3
3
  RSpec.describe Faraday::Request::Authorization do
4
4
  let(:conn) do
5
5
  Faraday.new do |b|
6
- b.request auth_type, *auth_config
6
+ b.request :authorization, auth_type, *auth_config
7
7
  b.adapter :test do |stub|
8
8
  stub.get('/auth-echo') do |env|
9
9
  [200, {}, env[:request_headers]['Authorization']]
@@ -14,10 +14,10 @@ RSpec.describe Faraday::Request::Authorization do
14
14
 
15
15
  shared_examples 'does not interfere with existing authentication' do
16
16
  context 'and request already has an authentication header' do
17
- let(:response) { conn.get('/auth-echo', nil, authorization: 'Token token="bar"') }
17
+ let(:response) { conn.get('/auth-echo', nil, authorization: 'OAuth oauth_token') }
18
18
 
19
19
  it 'does not interfere with existing authorization' do
20
- expect(response.body).to eq('Token token="bar"')
20
+ expect(response.body).to eq('OAuth oauth_token')
21
21
  end
22
22
  end
23
23
  end
@@ -25,7 +25,7 @@ RSpec.describe Faraday::Request::Authorization do
25
25
  let(:response) { conn.get('/auth-echo') }
26
26
 
27
27
  describe 'basic_auth' do
28
- let(:auth_type) { :basic_auth }
28
+ let(:auth_type) { :basic }
29
29
 
30
30
  context 'when passed correct params' do
31
31
  let(:auth_config) { %w[aladdin opensesame] }
@@ -44,43 +44,38 @@ RSpec.describe Faraday::Request::Authorization do
44
44
  end
45
45
  end
46
46
 
47
- describe 'token_auth' do
48
- let(:auth_type) { :token_auth }
47
+ describe 'authorization' do
48
+ let(:auth_type) { :Bearer }
49
49
 
50
- context 'when passed correct params' do
51
- let(:auth_config) { 'quux' }
50
+ context 'when passed a string' do
51
+ let(:auth_config) { ['custom'] }
52
52
 
53
- it { expect(response.body).to eq('Token token="quux"') }
53
+ it { expect(response.body).to eq('Bearer custom') }
54
54
 
55
55
  include_examples 'does not interfere with existing authentication'
56
56
  end
57
57
 
58
- context 'when other values are provided' do
59
- let(:auth_config) { ['baz', foo: 42] }
58
+ context 'when passed a proc' do
59
+ let(:auth_config) { [-> { 'custom_from_proc' }] }
60
60
 
61
- it { expect(response.body).to match(/^Token /) }
62
- it { expect(response.body).to match(/token="baz"/) }
63
- it { expect(response.body).to match(/foo="42"/) }
61
+ it { expect(response.body).to eq('Bearer custom_from_proc') }
64
62
 
65
63
  include_examples 'does not interfere with existing authentication'
66
64
  end
67
- end
68
-
69
- describe 'authorization' do
70
- let(:auth_type) { :authorization }
71
65
 
72
- context 'when passed two strings' do
73
- let(:auth_config) { ['custom', 'abc def'] }
66
+ context 'when passed a callable' do
67
+ let(:callable) { double('Callable Authorizer', call: 'custom_from_callable') }
68
+ let(:auth_config) { [callable] }
74
69
 
75
- it { expect(response.body).to eq('custom abc def') }
70
+ it { expect(response.body).to eq('Bearer custom_from_callable') }
76
71
 
77
72
  include_examples 'does not interfere with existing authentication'
78
73
  end
79
74
 
80
- context 'when passed a string and a hash' do
81
- let(:auth_config) { ['baz', foo: 42] }
75
+ context 'when passed too many arguments' do
76
+ let(:auth_config) { %w[baz foo] }
82
77
 
83
- it { expect(response.body).to eq('baz foo="42"') }
78
+ it { expect { response }.to raise_error(ArgumentError) }
84
79
 
85
80
  include_examples 'does not interfere with existing authentication'
86
81
  end
@@ -30,13 +30,11 @@ RSpec.describe Faraday::Request::Instrumentation do
30
30
 
31
31
  it { expect(options.name).to eq('request.faraday') }
32
32
  it 'defaults to ActiveSupport::Notifications' do
33
- begin
34
- res = options.instrumenter
35
- rescue NameError => e
36
- expect(e.to_s).to match('ActiveSupport')
37
- else
38
- expect(res).to eq(ActiveSupport::Notifications)
39
- end
33
+ res = options.instrumenter
34
+ rescue NameError => e
35
+ expect(e.to_s).to match('ActiveSupport')
36
+ else
37
+ expect(res).to eq(ActiveSupport::Notifications)
40
38
  end
41
39
 
42
40
  it 'instruments with default name' do
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Request::Json do
4
+ let(:middleware) { described_class.new(->(env) { Faraday::Response.new(env) }) }
5
+
6
+ def process(body, content_type = nil)
7
+ env = { body: body, request_headers: Faraday::Utils::Headers.new }
8
+ env[:request_headers]['content-type'] = content_type if content_type
9
+ middleware.call(Faraday::Env.from(env)).env
10
+ end
11
+
12
+ def result_body
13
+ result[:body]
14
+ end
15
+
16
+ def result_type
17
+ result[:request_headers]['content-type']
18
+ end
19
+
20
+ context 'no body' do
21
+ let(:result) { process(nil) }
22
+
23
+ it "doesn't change body" do
24
+ expect(result_body).to be_nil
25
+ end
26
+
27
+ it "doesn't add content type" do
28
+ expect(result_type).to be_nil
29
+ end
30
+ end
31
+
32
+ context 'empty body' do
33
+ let(:result) { process('') }
34
+
35
+ it "doesn't change body" do
36
+ expect(result_body).to be_empty
37
+ end
38
+
39
+ it "doesn't add content type" do
40
+ expect(result_type).to be_nil
41
+ end
42
+ end
43
+
44
+ context 'string body' do
45
+ let(:result) { process('{"a":1}') }
46
+
47
+ it "doesn't change body" do
48
+ expect(result_body).to eq('{"a":1}')
49
+ end
50
+
51
+ it 'adds content type' do
52
+ expect(result_type).to eq('application/json')
53
+ end
54
+ end
55
+
56
+ context 'object body' do
57
+ let(:result) { process(a: 1) }
58
+
59
+ it 'encodes body' do
60
+ expect(result_body).to eq('{"a":1}')
61
+ end
62
+
63
+ it 'adds content type' do
64
+ expect(result_type).to eq('application/json')
65
+ end
66
+ end
67
+
68
+ context 'empty object body' do
69
+ let(:result) { process({}) }
70
+
71
+ it 'encodes body' do
72
+ expect(result_body).to eq('{}')
73
+ end
74
+ end
75
+
76
+ context 'object body with json type' do
77
+ let(:result) { process({ a: 1 }, 'application/json; charset=utf-8') }
78
+
79
+ it 'encodes body' do
80
+ expect(result_body).to eq('{"a":1}')
81
+ end
82
+
83
+ it "doesn't change content type" do
84
+ expect(result_type).to eq('application/json; charset=utf-8')
85
+ end
86
+ end
87
+
88
+ context 'object body with vendor json type' do
89
+ let(:result) { process({ a: 1 }, 'application/vnd.myapp.v1+json; charset=utf-8') }
90
+
91
+ it 'encodes body' do
92
+ expect(result_body).to eq('{"a":1}')
93
+ end
94
+
95
+ it "doesn't change content type" do
96
+ expect(result_type).to eq('application/vnd.myapp.v1+json; charset=utf-8')
97
+ end
98
+ end
99
+
100
+ context 'object body with incompatible type' do
101
+ let(:result) { process({ a: 1 }, 'application/xml; charset=utf-8') }
102
+
103
+ it "doesn't change body" do
104
+ expect(result_body).to eq(a: 1)
105
+ end
106
+
107
+ it "doesn't change content type" do
108
+ expect(result_type).to eq('application/xml; charset=utf-8')
109
+ end
110
+ end
111
+ end
@@ -3,7 +3,6 @@
3
3
  RSpec.describe Faraday::Request::UrlEncoded do
4
4
  let(:conn) do
5
5
  Faraday.new do |b|
6
- b.request :multipart
7
6
  b.request :url_encoded
8
7
  b.adapter :test do |stub|
9
8
  stub.post('/echo') do |env|
@@ -67,4 +66,17 @@ RSpec.describe Faraday::Request::UrlEncoded do
67
66
  response = conn.post('/echo', 'a' => { 'b' => { 'c' => ['d'] } })
68
67
  expect(response.body).to eq('a%5Bb%5D%5Bc%5D%5B%5D=d')
69
68
  end
69
+
70
+ context 'customising default_space_encoding' do
71
+ around do |example|
72
+ Faraday::Utils.default_space_encoding = '%20'
73
+ example.run
74
+ Faraday::Utils.default_space_encoding = nil
75
+ end
76
+
77
+ it 'uses the custom character to encode spaces' do
78
+ response = conn.post('/echo', str: 'apple banana')
79
+ expect(response.body).to eq('str=apple%20banana')
80
+ end
81
+ end
70
82
  end
@@ -6,20 +6,20 @@ RSpec.describe Faraday::Request do
6
6
  headers: { 'Mime-Version' => '1.0' },
7
7
  request: { oauth: { consumer_key: 'anonymous' } })
8
8
  end
9
- let(:method) { :get }
9
+ let(:http_method) { :get }
10
10
  let(:block) { nil }
11
11
 
12
- subject { conn.build_request(method, &block) }
12
+ subject { conn.build_request(http_method, &block) }
13
13
 
14
14
  context 'when nothing particular is configured' do
15
- it { expect(subject.method).to eq(:get) }
15
+ it { expect(subject.http_method).to eq(:get) }
16
16
  it { expect(subject.to_env(conn).ssl.verify).to be_falsey }
17
17
  end
18
18
 
19
- context 'when method is post' do
20
- let(:method) { :post }
19
+ context 'when HTTP method is post' do
20
+ let(:http_method) { :post }
21
21
 
22
- it { expect(subject.method).to eq(:post) }
22
+ it { expect(subject.http_method).to eq(:post) }
23
23
  end
24
24
 
25
25
  context 'when setting the url on setup with a URI' do
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Response::Json, type: :response do
4
+ let(:options) { {} }
5
+ let(:headers) { {} }
6
+ let(:middleware) do
7
+ described_class.new(lambda { |env|
8
+ Faraday::Response.new(env)
9
+ }, **options)
10
+ end
11
+
12
+ def process(body, content_type = 'application/json', options = {})
13
+ env = {
14
+ body: body, request: options,
15
+ request_headers: Faraday::Utils::Headers.new,
16
+ response_headers: Faraday::Utils::Headers.new(headers)
17
+ }
18
+ env[:response_headers]['content-type'] = content_type if content_type
19
+ yield(env) if block_given?
20
+ middleware.call(Faraday::Env.from(env))
21
+ end
22
+
23
+ context 'no type matching' do
24
+ it "doesn't change nil body" do
25
+ expect(process(nil).body).to be_nil
26
+ end
27
+
28
+ it 'nullifies empty body' do
29
+ expect(process('').body).to be_nil
30
+ end
31
+
32
+ it 'parses json body' do
33
+ response = process('{"a":1}')
34
+ expect(response.body).to eq('a' => 1)
35
+ expect(response.env[:raw_body]).to be_nil
36
+ end
37
+ end
38
+
39
+ context 'with preserving raw' do
40
+ let(:options) { { preserve_raw: true } }
41
+
42
+ it 'parses json body' do
43
+ response = process('{"a":1}')
44
+ expect(response.body).to eq('a' => 1)
45
+ expect(response.env[:raw_body]).to eq('{"a":1}')
46
+ end
47
+ end
48
+
49
+ context 'with default regexp type matching' do
50
+ it 'parses json body of correct type' do
51
+ response = process('{"a":1}', 'application/x-json')
52
+ expect(response.body).to eq('a' => 1)
53
+ end
54
+
55
+ it 'ignores json body of incorrect type' do
56
+ response = process('{"a":1}', 'text/json-xml')
57
+ expect(response.body).to eq('{"a":1}')
58
+ end
59
+ end
60
+
61
+ context 'with array type matching' do
62
+ let(:options) { { content_type: %w[a/b c/d] } }
63
+
64
+ it 'parses json body of correct type' do
65
+ expect(process('{"a":1}', 'a/b').body).to be_a(Hash)
66
+ expect(process('{"a":1}', 'c/d').body).to be_a(Hash)
67
+ end
68
+
69
+ it 'ignores json body of incorrect type' do
70
+ expect(process('{"a":1}', 'a/d').body).not_to be_a(Hash)
71
+ end
72
+ end
73
+
74
+ it 'chokes on invalid json' do
75
+ expect { process('{!') }.to raise_error(Faraday::ParsingError)
76
+ end
77
+
78
+ it 'includes the response on the ParsingError instance' do
79
+ process('{') { |env| env[:response] = Faraday::Response.new }
80
+ raise 'Parsing should have failed.'
81
+ rescue Faraday::ParsingError => e
82
+ expect(e.response).to be_a(Faraday::Response)
83
+ end
84
+
85
+ context 'HEAD responses' do
86
+ it "nullifies the body if it's only one space" do
87
+ response = process(' ')
88
+ expect(response.body).to be_nil
89
+ end
90
+
91
+ it "nullifies the body if it's two spaces" do
92
+ response = process(' ')
93
+ expect(response.body).to be_nil
94
+ end
95
+ end
96
+
97
+ context 'JSON options' do
98
+ let(:body) { '{"a": 1}' }
99
+ let(:result) { { a: 1 } }
100
+ let(:options) do
101
+ {
102
+ parser_options: {
103
+ symbolize_names: true
104
+ }
105
+ }
106
+ end
107
+
108
+ it 'passes relevant options to JSON parse' do
109
+ expect(::JSON).to receive(:parse)
110
+ .with(body, options[:parser_options])
111
+ .and_return(result)
112
+
113
+ response = process(body)
114
+ expect(response.body).to eq(result)
115
+ end
116
+ end
117
+ end