webmock 3.0.1 → 3.18.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/CI.yml +38 -0
  3. data/CHANGELOG.md +496 -2
  4. data/Gemfile +1 -1
  5. data/README.md +169 -34
  6. data/Rakefile +12 -4
  7. data/lib/webmock/api.rb +12 -0
  8. data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +221 -0
  9. data/lib/webmock/http_lib_adapters/curb_adapter.rb +19 -5
  10. data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +7 -4
  11. data/lib/webmock/http_lib_adapters/excon_adapter.rb +5 -2
  12. data/lib/webmock/http_lib_adapters/http_rb/client.rb +2 -1
  13. data/lib/webmock/http_lib_adapters/http_rb/request.rb +7 -1
  14. data/lib/webmock/http_lib_adapters/http_rb/response.rb +27 -3
  15. data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +9 -3
  16. data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +7 -3
  17. data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +28 -9
  18. data/lib/webmock/http_lib_adapters/manticore_adapter.rb +33 -15
  19. data/lib/webmock/http_lib_adapters/net_http.rb +36 -89
  20. data/lib/webmock/http_lib_adapters/net_http_response.rb +1 -1
  21. data/lib/webmock/http_lib_adapters/patron_adapter.rb +4 -4
  22. data/lib/webmock/matchers/any_arg_matcher.rb +13 -0
  23. data/lib/webmock/matchers/hash_argument_matcher.rb +21 -0
  24. data/lib/webmock/matchers/hash_excluding_matcher.rb +15 -0
  25. data/lib/webmock/matchers/hash_including_matcher.rb +4 -23
  26. data/lib/webmock/rack_response.rb +1 -1
  27. data/lib/webmock/request_body_diff.rb +1 -1
  28. data/lib/webmock/request_execution_verifier.rb +2 -3
  29. data/lib/webmock/request_pattern.rb +129 -51
  30. data/lib/webmock/request_registry.rb +1 -1
  31. data/lib/webmock/request_signature.rb +3 -3
  32. data/lib/webmock/request_signature_snippet.rb +4 -4
  33. data/lib/webmock/request_stub.rb +15 -0
  34. data/lib/webmock/response.rb +19 -13
  35. data/lib/webmock/rspec.rb +10 -3
  36. data/lib/webmock/stub_registry.rb +26 -11
  37. data/lib/webmock/stub_request_snippet.rb +10 -6
  38. data/lib/webmock/test_unit.rb +1 -3
  39. data/lib/webmock/util/hash_counter.rb +3 -3
  40. data/lib/webmock/util/headers.rb +17 -2
  41. data/lib/webmock/util/json.rb +1 -2
  42. data/lib/webmock/util/query_mapper.rb +9 -7
  43. data/lib/webmock/util/uri.rb +10 -10
  44. data/lib/webmock/util/values_stringifier.rb +20 -0
  45. data/lib/webmock/version.rb +1 -1
  46. data/lib/webmock/webmock.rb +20 -3
  47. data/lib/webmock.rb +53 -48
  48. data/minitest/webmock_spec.rb +3 -3
  49. data/spec/acceptance/async_http_client/async_http_client_spec.rb +375 -0
  50. data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
  51. data/spec/acceptance/curb/curb_spec.rb +44 -0
  52. data/spec/acceptance/em_http_request/em_http_request_spec.rb +57 -1
  53. data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +2 -2
  54. data/spec/acceptance/excon/excon_spec.rb +4 -2
  55. data/spec/acceptance/excon/excon_spec_helper.rb +2 -0
  56. data/spec/acceptance/http_rb/http_rb_spec.rb +20 -0
  57. data/spec/acceptance/http_rb/http_rb_spec_helper.rb +5 -2
  58. data/spec/acceptance/httpclient/httpclient_spec.rb +8 -1
  59. data/spec/acceptance/manticore/manticore_spec.rb +51 -0
  60. data/spec/acceptance/net_http/net_http_shared.rb +47 -10
  61. data/spec/acceptance/net_http/net_http_spec.rb +102 -24
  62. data/spec/acceptance/net_http/real_net_http_spec.rb +1 -1
  63. data/spec/acceptance/patron/patron_spec.rb +26 -21
  64. data/spec/acceptance/patron/patron_spec_helper.rb +3 -3
  65. data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +14 -14
  66. data/spec/acceptance/shared/callbacks.rb +3 -2
  67. data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +1 -1
  68. data/spec/acceptance/shared/request_expectations.rb +14 -0
  69. data/spec/acceptance/shared/returning_declared_responses.rb +36 -15
  70. data/spec/acceptance/shared/stubbing_requests.rb +95 -0
  71. data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +1 -1
  72. data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +1 -1
  73. data/spec/support/webmock_server.rb +1 -0
  74. data/spec/unit/api_spec.rb +103 -3
  75. data/spec/unit/matchers/hash_excluding_matcher_spec.rb +61 -0
  76. data/spec/unit/request_execution_verifier_spec.rb +12 -12
  77. data/spec/unit/request_pattern_spec.rb +207 -49
  78. data/spec/unit/request_signature_snippet_spec.rb +2 -2
  79. data/spec/unit/request_signature_spec.rb +21 -1
  80. data/spec/unit/request_stub_spec.rb +35 -0
  81. data/spec/unit/response_spec.rb +51 -19
  82. data/spec/unit/stub_request_snippet_spec.rb +30 -10
  83. data/spec/unit/util/query_mapper_spec.rb +13 -0
  84. data/spec/unit/util/uri_spec.rb +74 -2
  85. data/spec/unit/webmock_spec.rb +108 -5
  86. data/test/shared_test.rb +15 -2
  87. data/test/test_webmock.rb +6 -0
  88. data/webmock.gemspec +15 -7
  89. metadata +86 -37
  90. data/.travis.yml +0 -20
@@ -58,7 +58,7 @@ describe WebMock::RequestPattern do
58
58
  end
59
59
 
60
60
  it "should raise an error if neither options or block is provided" do
61
- expect { @request_pattern.with() }.to raise_error('#with method invoked with no arguments. Either options hash or block must be specified.')
61
+ expect { @request_pattern.with() }.to raise_error('#with method invoked with no arguments. Either options hash or block must be specified. Created a block with do..end? Try creating it with curly braces {} instead.')
62
62
  end
63
63
  end
64
64
 
@@ -111,6 +111,21 @@ describe WebMock::RequestPattern do
111
111
  to match(WebMock::RequestSignature.new(:get, "www.example.com"))
112
112
  end
113
113
 
114
+ it "should match if uri matches requesst uri as URI object" do
115
+ expect(WebMock::RequestPattern.new(:get, URI.parse("www.example.com"))).
116
+ to match(WebMock::RequestSignature.new(:get, "www.example.com"))
117
+ end
118
+
119
+ it "should match if uri proc pattern returning true" do
120
+ expect(WebMock::RequestPattern.new(:get, ->(uri) { true })).
121
+ to match(WebMock::RequestSignature.new(:get, "www.example.com"))
122
+ end
123
+
124
+ it "should not match if uri proc pattern returns false" do
125
+ expect(WebMock::RequestPattern.new(:get, ->(uri) { false })).
126
+ not_to match(WebMock::RequestSignature.new(:get, "www.example.com"))
127
+ end
128
+
114
129
  it "should match if uri Addressable::Template pattern matches unescaped form of request uri" do
115
130
  expect(WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com/{any_path}"))).
116
131
  to match(WebMock::RequestSignature.new(:get, "www.example.com/my%20path"))
@@ -121,6 +136,41 @@ describe WebMock::RequestPattern do
121
136
  to match(WebMock::RequestSignature.new(:get, "www.example.com"))
122
137
  end
123
138
 
139
+ it "should match if uri Addressable::Template pattern matches request uri without TLD" do
140
+ expect(WebMock::RequestPattern.new(:get, Addressable::Template.new("localhost"))).
141
+ to match(WebMock::RequestSignature.new(:get, "localhost"))
142
+ end
143
+
144
+ it "should match if Addressable::Template pattern that has ip address host matches request uri" do
145
+ signature = WebMock::RequestSignature.new(:get, "127.0.0.1:3000/1234")
146
+ uri = Addressable::Template.new("127.0.0.1:3000/{id}")
147
+ expect(WebMock::RequestPattern.new(:get, uri)).to match(signature)
148
+ end
149
+
150
+ it "should match if Addressable::Template pattern that has ip address host without port matches request uri" do
151
+ signature = WebMock::RequestSignature.new(:get, "127.0.0.1/1234")
152
+ uri = Addressable::Template.new("127.0.0.1/{id}")
153
+ expect(WebMock::RequestPattern.new(:get, uri)).to match(signature)
154
+ end
155
+
156
+ it "should match if Addressable::Template pattern host matches request uri" do
157
+ signature = WebMock::RequestSignature.new(:get, "www.example.com")
158
+ uri = Addressable::Template.new("{subdomain}.example.com")
159
+ expect(WebMock::RequestPattern.new(:get, uri)).to match(signature)
160
+ end
161
+
162
+ it "should not match if Addressable::Template pattern host does not match request uri" do
163
+ signature = WebMock::RequestSignature.new(:get, "www.bad-example.com")
164
+ uri = Addressable::Template.new("{subdomain}.example.com")
165
+ expect(WebMock::RequestPattern.new(:get, uri)).not_to match(signature)
166
+ end
167
+
168
+ it "should match if uri Addressable::Template pattern matches request uri without a schema and a path " do
169
+ signature = WebMock::RequestSignature.new(:get, "127.0.0.1:3000")
170
+ uri = Addressable::Template.new("127.0.0.1:3000")
171
+ expect(WebMock::RequestPattern.new(:get, uri)).to match(signature)
172
+ end
173
+
124
174
  it "should match for uris with same parameters as pattern" do
125
175
  expect(WebMock::RequestPattern.new(:get, "www.example.com?a=1&b=2")).
126
176
  to match(WebMock::RequestSignature.new(:get, "www.example.com?a=1&b=2"))
@@ -188,7 +238,7 @@ describe WebMock::RequestPattern do
188
238
  to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c"))
189
239
  end
190
240
 
191
- it "should match request query params if params don't match" do
241
+ it "should not match request query params if params don't match" do
192
242
  expect(WebMock::RequestPattern.new(:get, /.*example.*/, query: {"x" => ["b", "c"]})).
193
243
  not_to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c"))
194
244
  end
@@ -218,13 +268,85 @@ describe WebMock::RequestPattern do
218
268
  end
219
269
  end
220
270
 
271
+ describe "when uri is described as URI" do
272
+ it "should match request query params" do
273
+ expect(WebMock::RequestPattern.new(:get, URI.parse("www.example.com"), query: {"a" => ["b", "c"]})).
274
+ to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c"))
275
+ end
276
+
277
+ it "should not match request query params if params don't match" do
278
+ expect(WebMock::RequestPattern.new(:get, URI.parse("www.example.com"), query: {"x" => ["b", "c"]})).
279
+ not_to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c"))
280
+ end
281
+
282
+ it "should match when query params are declared as HashIncluding matcher matching params" do
283
+ expect(WebMock::RequestPattern.new(:get, URI.parse("www.example.com"),
284
+ query: WebMock::Matchers::HashIncludingMatcher.new({"a" => ["b", "c"]}))).
285
+ to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c&b=1"))
286
+ end
287
+
288
+ it "should not match when query params are declared as HashIncluding matcher not matching params" do
289
+ expect(WebMock::RequestPattern.new(:get, URI.parse("www.example.com"),
290
+ query: WebMock::Matchers::HashIncludingMatcher.new({"x" => ["b", "c"]}))).
291
+ not_to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c&b=1"))
292
+ end
293
+
294
+ it "should match when query params are declared as RSpec HashIncluding matcher matching params" do
295
+ expect(WebMock::RequestPattern.new(:get, URI.parse("www.example.com"),
296
+ query: RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher.new({"a" => ["b", "c"]}))).
297
+ to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c&b=1"))
298
+ end
299
+
300
+ it "should not match when query params are declared as RSpec HashIncluding matcher not matching params" do
301
+ expect(WebMock::RequestPattern.new(:get, URI.parse("www.example.com"),
302
+ query: RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher.new({"a" => ["b", "d"]}))).
303
+ not_to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c&b=1"))
304
+ end
305
+ end
306
+
307
+ describe "when uri is described as a proc" do
308
+ it "should match request query params" do
309
+ expect(WebMock::RequestPattern.new(:get, ->(uri) { true }, query: {"a" => ["b", "c"]})).
310
+ to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c"))
311
+ end
312
+
313
+ it "should not match request query params if params don't match" do
314
+ expect(WebMock::RequestPattern.new(:get, ->(uri) { true }, query: {"x" => ["b", "c"]})).
315
+ not_to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c"))
316
+ end
317
+
318
+ it "should match when query params are declared as HashIncluding matcher matching params" do
319
+ expect(WebMock::RequestPattern.new(:get, ->(uri) { true },
320
+ query: WebMock::Matchers::HashIncludingMatcher.new({"a" => ["b", "c"]}))).
321
+ to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c&b=1"))
322
+ end
323
+
324
+ it "should not match when query params are declared as HashIncluding matcher not matching params" do
325
+ expect(WebMock::RequestPattern.new(:get, ->(uri) { true },
326
+ query: WebMock::Matchers::HashIncludingMatcher.new({"x" => ["b", "c"]}))).
327
+ not_to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c&b=1"))
328
+ end
329
+
330
+ it "should match when query params are declared as RSpec HashIncluding matcher matching params" do
331
+ expect(WebMock::RequestPattern.new(:get, ->(uri) { true },
332
+ query: RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher.new({"a" => ["b", "c"]}))).
333
+ to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c&b=1"))
334
+ end
335
+
336
+ it "should not match when query params are declared as RSpec HashIncluding matcher not matching params" do
337
+ expect(WebMock::RequestPattern.new(:get, ->(uri) { true },
338
+ query: RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher.new({"a" => ["b", "d"]}))).
339
+ not_to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c&b=1"))
340
+ end
341
+ end
342
+
221
343
  describe "when uri is described as Addressable::Template" do
222
344
  it "should raise error if query params are specified" do
223
345
  expect(WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com"), query: {"a" => ["b", "c"]})).
224
346
  to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c"))
225
347
  end
226
348
 
227
- it "should match request query params if params don't match" do
349
+ it "should not match request query params if params don't match" do
228
350
  expect(WebMock::RequestPattern.new(:get, Addressable::Template.new("www.example.com"), query: {"x" => ["b", "c"]})).
229
351
  not_to match(WebMock::RequestSignature.new(:get, "www.example.com?a[]=b&a[]=c"))
230
352
  end
@@ -412,69 +534,105 @@ describe WebMock::RequestPattern do
412
534
  end
413
535
 
414
536
  describe "for request with json body and content type is set to json" do
415
- it "should match when hash matches body" do
416
- expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
417
- to match(WebMock::RequestSignature.new(:post, "www.example.com", headers: {content_type: 'application/json'},
418
- body: "{\"a\":\"1\",\"c\":{\"d\":[\"e\",\"f\"]},\"b\":\"five\"}"))
419
- end
537
+ shared_examples "a json body" do
538
+ it "should match when hash matches body" do
539
+ expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
540
+ to match(WebMock::RequestSignature.new(:post, "www.example.com", headers: {content_type: content_type},
541
+ body: "{\"a\":\"1\",\"c\":{\"d\":[\"e\",\"f\"]},\"b\":\"five\"}"))
542
+ end
420
543
 
421
- it "should match if hash matches body in different form" do
422
- expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
423
- to match(WebMock::RequestSignature.new(:post, "www.example.com", headers: {content_type: 'application/json'},
424
- body: "{\"a\":\"1\",\"b\":\"five\",\"c\":{\"d\":[\"e\",\"f\"]}}"))
425
- end
544
+ it "should match if hash matches body in different form" do
545
+ expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
546
+ to match(WebMock::RequestSignature.new(:post, "www.example.com", headers: {content_type: content_type},
547
+ body: "{\"a\":\"1\",\"b\":\"five\",\"c\":{\"d\":[\"e\",\"f\"]}}"))
548
+ end
549
+
550
+ it "should match if the request body has a top level array" do
551
+ expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: [{a: 1}])).
552
+ to match(WebMock::RequestSignature.new(:post, "www.example.com",
553
+ headers: {content_type: content_type}, body: "[{\"a\":1}]"))
554
+ end
426
555
 
427
- it "should not match when body is not json" do
428
- expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
429
- not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
430
- headers: {content_type: 'application/json'}, body: "foo bar"))
431
- end
556
+ it "should not match if the request body has a different top level array" do
557
+ expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: ["a", "b"])).
558
+ not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
559
+ headers: {content_type: content_type}, body: "[\"a\", \"c\"]"))
560
+ end
561
+
562
+ it "should not match when body is not json" do
563
+ expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
564
+ not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
565
+ headers: {content_type: content_type}, body: "foo bar"))
566
+ end
432
567
 
433
- it "should not match if request body is different" do
434
- expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: {a: 1, b: 2})).
435
- not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
436
- headers: {content_type: 'application/json'}, body: "{\"a\":1,\"c\":null}"))
568
+ it "should not match if request body is different" do
569
+ expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: {a: 1, b: 2})).
570
+ not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
571
+ headers: {content_type: content_type}, body: "{\"a\":1,\"c\":null}"))
572
+ end
573
+
574
+ it "should not match if request body is has less params than pattern" do
575
+ expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: {a: 1, b: 2})).
576
+ not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
577
+ headers: {content_type: content_type}, body: "{\"a\":1}"))
578
+ end
579
+
580
+ it "should not match if request body is has more params than pattern" do
581
+ expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: {a: 1})).
582
+ not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
583
+ headers: {content_type: content_type}, body: "{\"a\":1,\"c\":1}"))
584
+ end
437
585
  end
438
586
 
439
- it "should not match if request body is has less params than pattern" do
440
- expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: {a: 1, b: 2})).
441
- not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
442
- headers: {content_type: 'application/json'}, body: "{\"a\":1}"))
587
+ context "standard application/json" do
588
+ let(:content_type) { 'application/json' }
589
+ it_behaves_like "a json body"
443
590
  end
444
591
 
445
- it "should not match if request body is has more params than pattern" do
446
- expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: {a: 1})).
447
- not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
448
- headers: {content_type: 'application/json'}, body: "{\"a\":1,\"c\":1}"))
592
+ context "custom json content type" do
593
+ let(:content_type) { 'application/vnd.api+json' }
594
+ it_behaves_like "a json body"
449
595
  end
450
596
  end
451
597
 
452
598
  describe "for request with xml body and content type is set to xml" do
453
599
  let(:body_hash) { {"opt" => {:a => '1', :b => 'five', 'c' => {'d' => ['e', 'f']}}} }
454
600
 
455
- it "should match when hash matches body" do
456
- expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
457
- to match(WebMock::RequestSignature.new(:post, "www.example.com", headers: {content_type: 'application/xml'},
458
- body: "<opt a=\"1\" b=\"five\">\n <c>\n <d>e</d>\n <d>f</d>\n </c>\n</opt>\n"))
459
- end
601
+ shared_examples "a xml body" do
602
+ it "should match when hash matches body" do
603
+ expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
604
+ to match(WebMock::RequestSignature.new(:post, "www.example.com", headers: {content_type: content_type},
605
+ body: "<opt a=\"1\" b=\"five\">\n <c>\n <d>e</d>\n <d>f</d>\n </c>\n</opt>\n"))
606
+ end
460
607
 
461
- it "should match if hash matches body in different form" do
462
- expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
463
- to match(WebMock::RequestSignature.new(:post, "www.example.com", headers: {content_type: 'application/xml'},
464
- body: "<opt b=\"five\" a=\"1\">\n <c>\n <d>e</d>\n <d>f</d>\n </c>\n</opt>\n"))
465
- end
608
+ it "should match if hash matches body in different form" do
609
+ expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
610
+ to match(WebMock::RequestSignature.new(:post, "www.example.com", headers: {content_type: content_type},
611
+ body: "<opt b=\"five\" a=\"1\">\n <c>\n <d>e</d>\n <d>f</d>\n </c>\n</opt>\n"))
612
+ end
466
613
 
467
- it "should not match when body is not xml" do
468
- expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
469
- not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
470
- headers: {content_type: 'application/xml'}, body: "foo bar"))
471
- end
614
+ it "should not match when body is not xml" do
615
+ expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
616
+ not_to match(WebMock::RequestSignature.new(:post, "www.example.com",
617
+ headers: {content_type: content_type}, body: "foo bar"))
618
+ end
472
619
 
473
- it "matches when the content type include a charset" do
474
- expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
475
- to match(WebMock::RequestSignature.new(:post, "www.example.com", headers: {content_type: 'application/xml;charset=UTF-8'},
476
- body: "<opt a=\"1\" b=\"five\">\n <c>\n <d>e</d>\n <d>f</d>\n </c>\n</opt>\n"))
620
+ it "matches when the content type include a charset" do
621
+ expect(WebMock::RequestPattern.new(:post, 'www.example.com', body: body_hash)).
622
+ to match(WebMock::RequestSignature.new(:post, "www.example.com", headers: {content_type: "#{content_type};charset=UTF-8"},
623
+ body: "<opt a=\"1\" b=\"five\">\n <c>\n <d>e</d>\n <d>f</d>\n </c>\n</opt>\n"))
624
+
625
+ end
626
+ end
627
+
628
+ context "standard application/xml" do
629
+ let(:content_type) { 'application/xml' }
630
+ it_behaves_like "a xml body"
631
+ end
477
632
 
633
+ context "custom xml content type" do
634
+ let(:content_type) { 'application/atom+xml' }
635
+ it_behaves_like "a xml body"
478
636
  end
479
637
  end
480
638
  end
@@ -60,7 +60,7 @@ RSpec.describe WebMock::RequestSignatureSnippet do
60
60
  result = subject.request_stubs
61
61
  result.sub!("registered request stubs:\n\n", "")
62
62
  expect(result).to eq(
63
- "stub_request(:get, \"https://www.example.com/\").\n with(body: {\"a\"=>\"b\"})"
63
+ "stub_request(:get, \"https://www.example.com/\").\n with(\n body: {\"a\"=>\"b\"})"
64
64
  )
65
65
  end
66
66
 
@@ -74,7 +74,7 @@ RSpec.describe WebMock::RequestSignatureSnippet do
74
74
  result = subject.request_stubs
75
75
  result.sub!("registered request stubs:\n\n", "")
76
76
  expect(result).to eq(
77
- "stub_request(:get, \"https://www.example.com/\").\n with(body: {\"a\"=>\"b\"})\n\nBody diff:\n [[\"-\", \"key\", \"different value\"], [\"+\", \"a\", \"b\"]]\n"
77
+ "stub_request(:get, \"https://www.example.com/\").\n with(\n body: {\"a\"=>\"b\"})\n\nBody diff:\n [[\"-\", \"key\", \"different value\"], [\"+\", \"a\", \"b\"]]\n"
78
78
  )
79
79
  end
80
80
  end
@@ -18,7 +18,7 @@ describe WebMock::RequestSignature do
18
18
  end
19
19
 
20
20
  it "assigns normalized headers" do
21
- expect(WebMock::Util::Headers).to receive(:normalize_headers).with('A' => 'a').and_return('B' => 'b')
21
+ allow(WebMock::Util::Headers).to receive(:normalize_headers).with({'A' => 'a'}.freeze).and_return('B' => 'b')
22
22
  expect(
23
23
  WebMock::RequestSignature.new(:get, "www.example.com", headers: {'A' => 'a'}).headers
24
24
  ).to eq({'B' => 'b'})
@@ -125,11 +125,21 @@ describe WebMock::RequestSignature do
125
125
  expect(subject.url_encoded?).to be true
126
126
  end
127
127
 
128
+ it "returns true if the headers are urlencoded with a specified charset" do
129
+ subject.headers = { "Content-Type" => "application/x-www-form-urlencoded; charset=UTF-8" }
130
+ expect(subject.url_encoded?).to be true
131
+ end
132
+
128
133
  it "returns false if the headers are NOT urlencoded" do
129
134
  subject.headers = { "Content-Type" => "application/made-up-format" }
130
135
  expect(subject.url_encoded?).to be false
131
136
  end
132
137
 
138
+ it "returns false when no content type header is present" do
139
+ subject.headers = { "Some-Header" => "some-value" }
140
+ expect(subject.url_encoded?).to be false
141
+ end
142
+
133
143
  it "returns false when no headers are set" do
134
144
  subject.headers = nil
135
145
  expect(subject.url_encoded?).to be false
@@ -142,11 +152,21 @@ describe WebMock::RequestSignature do
142
152
  expect(subject.json_headers?).to be true
143
153
  end
144
154
 
155
+ it "returns true if the headers are json with a specified charset" do
156
+ subject.headers = { "Content-Type" => "application/json; charset=UTF-8" }
157
+ expect(subject.json_headers?).to be true
158
+ end
159
+
145
160
  it "returns false if the headers are NOT json" do
146
161
  subject.headers = { "Content-Type" => "application/made-up-format" }
147
162
  expect(subject.json_headers?).to be false
148
163
  end
149
164
 
165
+ it "returns false when no content type header is present" do
166
+ subject.headers = { "Some-Header" => "some-value" }
167
+ expect(subject.json_headers?).to be false
168
+ end
169
+
150
170
  it "returns false when no headers are set" do
151
171
  subject.headers = nil
152
172
  expect(subject.json_headers?).to be false
@@ -50,6 +50,41 @@ describe WebMock::RequestStub do
50
50
 
51
51
  end
52
52
 
53
+ describe "to_return_json" do
54
+
55
+ it "should raise if a block is given" do
56
+ expect {
57
+ @request_stub.to_return_json(body: "abc", status: 500) { puts "don't call me" }
58
+ }.to raise_error(ArgumentError, '#to_return_json does not support passing a block')
59
+ end
60
+
61
+ it "should assign responses normally" do
62
+ @request_stub.to_return_json([{body: "abc"}, {body: "def"}])
63
+ expect([@request_stub.response.body, @request_stub.response.body]).to eq(["abc", "def"])
64
+ end
65
+
66
+ it "should json-ify a Hash body" do
67
+ @request_stub.to_return_json(body: {abc: "def"}, status: 500)
68
+ expect(@request_stub.response.body).to eq({abc: "def"}.to_json)
69
+ expect(@request_stub.response.status).to eq([500, ""])
70
+ end
71
+
72
+ it "should apply the content_type header" do
73
+ @request_stub.to_return_json(body: {abc: "def"}, status: 500)
74
+ expect(@request_stub.response.headers).to eq({"Content-Type"=>"application/json"})
75
+ end
76
+
77
+ it "should preserve existing headers" do
78
+ @request_stub.to_return_json(headers: {"A" => "a"}, body: "")
79
+ expect(@request_stub.response.headers).to eq({"A"=>"a", "Content-Type"=>"application/json"})
80
+ end
81
+
82
+ it "should allow callsites to override content_type header" do
83
+ @request_stub.to_return_json(headers: {content_type: 'application/super-special-json'})
84
+ expect(@request_stub.response.headers).to eq({"Content-Type"=>"application/super-special-json"})
85
+ end
86
+ end
87
+
53
88
  describe "then" do
54
89
  it "should return stub without any modifications, acting as syntactic sugar" do
55
90
  expect(@request_stub.then).to eq(@request_stub)
@@ -31,7 +31,7 @@ describe WebMock::Response do
31
31
  end
32
32
 
33
33
  it "should report normalized headers" do
34
- expect(WebMock::Util::Headers).to receive(:normalize_headers).with('A' => 'a').and_return('B' => 'b')
34
+ allow(WebMock::Util::Headers).to receive(:normalize_headers).with({'A' => 'a'}.freeze).and_return('B' => 'b')
35
35
  @response = WebMock::Response.new(headers: {'A' => 'a'})
36
36
  expect(@response.headers).to eq({'B' => 'b'})
37
37
  end
@@ -130,14 +130,46 @@ describe WebMock::Response do
130
130
  # Users of webmock commonly make the mistake of stubbing the response
131
131
  # body to return a hash, to prevent this:
132
132
  #
133
- it "should error if not given one of the allowed types" do
133
+ it "should error if given a non-allowed type: a hash" do
134
134
  expect { WebMock::Response.new(body: Hash.new) }.to \
135
135
  raise_error(WebMock::Response::InvalidBody)
136
136
  end
137
137
 
138
+ it "should error if given a non-allowed type: something that is not a hash" do
139
+ expect { WebMock::Response.new(body: 123) }.to \
140
+ raise_error(WebMock::Response::InvalidBody)
141
+ end
138
142
  end
139
143
 
140
144
  describe "from raw response" do
145
+ describe "when input is a StringIO" do
146
+ before(:each) do
147
+ @io = StringIO.new(File.read(CURL_EXAMPLE_OUTPUT_PATH))
148
+ @response = WebMock::Response.new(@io)
149
+ end
150
+
151
+ it "should read status" do
152
+ expect(@response.status).to eq([202, "OK"])
153
+ end
154
+
155
+ it "should read headers" do
156
+ expect(@response.headers).to eq(
157
+ "Date"=>"Sat, 23 Jan 2010 01:01:05 GMT",
158
+ "Content-Type"=>"text/html; charset=UTF-8",
159
+ "Content-Length"=>"419",
160
+ "Connection"=>"Keep-Alive",
161
+ "Accept"=>"image/jpeg, image/png"
162
+ )
163
+ end
164
+
165
+ it "should read body" do
166
+ expect(@response.body.size).to eq(419)
167
+ end
168
+
169
+ it "should close IO" do
170
+ expect(@io).to be_closed
171
+ end
172
+ end
141
173
 
142
174
  describe "when input is IO" do
143
175
  before(:each) do
@@ -152,12 +184,12 @@ describe WebMock::Response do
152
184
 
153
185
  it "should read headers" do
154
186
  expect(@response.headers).to eq({
155
- "Date"=>"Sat, 23 Jan 2010 01:01:05 GMT",
156
- "Content-Type"=>"text/html; charset=UTF-8",
157
- "Content-Length"=>"419",
158
- "Connection"=>"Keep-Alive",
159
- "Accept"=>"image/jpeg, image/png"
160
- })
187
+ "Date"=>"Sat, 23 Jan 2010 01:01:05 GMT",
188
+ "Content-Type"=>"text/html; charset=UTF-8",
189
+ "Content-Length"=>"419",
190
+ "Connection"=>"Keep-Alive",
191
+ "Accept"=>"image/jpeg, image/png"
192
+ })
161
193
  end
162
194
 
163
195
  it "should read body" do
@@ -182,12 +214,12 @@ describe WebMock::Response do
182
214
 
183
215
  it "should read headers" do
184
216
  expect(@response.headers).to eq({
185
- "Date"=>"Sat, 23 Jan 2010 01:01:05 GMT",
186
- "Content-Type"=>"text/html; charset=UTF-8",
187
- "Content-Length"=>"419",
188
- "Connection"=>"Keep-Alive",
189
- "Accept"=>"image/jpeg, image/png"
190
- })
217
+ "Date"=>"Sat, 23 Jan 2010 01:01:05 GMT",
218
+ "Content-Type"=>"text/html; charset=UTF-8",
219
+ "Content-Length"=>"419",
220
+ "Connection"=>"Keep-Alive",
221
+ "Accept"=>"image/jpeg, image/png"
222
+ })
191
223
  end
192
224
 
193
225
  it "should read body" do
@@ -234,11 +266,11 @@ describe WebMock::Response do
234
266
  it "should evaluate new response with evaluated options" do
235
267
  request_signature = WebMock::RequestSignature.new(:post, "www.example.com", body: "abc", headers: {'A' => 'a'})
236
268
  response = WebMock::DynamicResponse.new(lambda {|request|
237
- {
238
- body: request.body,
239
- headers: request.headers,
240
- status: 302
241
- }
269
+ {
270
+ body: request.body,
271
+ headers: request.headers,
272
+ status: 302
273
+ }
242
274
  })
243
275
  evaluated_response = response.evaluate(request_signature)
244
276
  expect(evaluated_response.body).to eq("abc")
@@ -16,7 +16,7 @@ describe WebMock::StubRequestSnippet do
16
16
  it "should print stub request snippet with body if available" do
17
17
  @request_signature.body = "abcdef"
18
18
  expected = %Q(stub_request(:get, "http://www.example.com/?a=b&c=d").)+
19
- "\n with(body: \"abcdef\")." +
19
+ "\n with(\n body: \"abcdef\")." +
20
20
  "\n to_return(status: 200, body: \"\", headers: {})"
21
21
  @request_stub = WebMock::RequestStub.from_request_signature(@request_signature)
22
22
  expect(WebMock::StubRequestSnippet.new(@request_stub).to_s).to eq(expected)
@@ -25,7 +25,7 @@ describe WebMock::StubRequestSnippet do
25
25
  it "should print stub request snippet with multiline body" do
26
26
  @request_signature.body = "abc\ndef"
27
27
  expected = %Q(stub_request(:get, "http://www.example.com/?a=b&c=d").)+
28
- "\n with(body: \"abc\\ndef\")." +
28
+ "\n with(\n body: \"abc\\ndef\")." +
29
29
  "\n to_return(status: 200, body: \"\", headers: {})"
30
30
  @request_stub = WebMock::RequestStub.from_request_signature(@request_signature)
31
31
  expect(WebMock::StubRequestSnippet.new(@request_stub).to_s).to eq(expected)
@@ -34,7 +34,7 @@ describe WebMock::StubRequestSnippet do
34
34
  it "should print stub request snippet with headers if any" do
35
35
  @request_signature.headers = {'B' => 'b', 'A' => 'a'}
36
36
  expected = 'stub_request(:get, "http://www.example.com/?a=b&c=d").'+
37
- "\n with(headers: {\'A\'=>\'a\', \'B\'=>\'b\'})." +
37
+ "\n with(\n headers: {\n\t\ 'A\'=>\'a\',\n\t \'B\'=>\'b\'\n })." +
38
38
  "\n to_return(status: 200, body: \"\", headers: {})"
39
39
  @request_stub = WebMock::RequestStub.from_request_signature(@request_signature)
40
40
  expect(WebMock::StubRequestSnippet.new(@request_stub).to_s).to eq(expected)
@@ -44,7 +44,7 @@ describe WebMock::StubRequestSnippet do
44
44
  @request_signature.body = "abcdef"
45
45
  @request_signature.headers = {'B' => 'b', 'A' => 'a'}
46
46
  expected = 'stub_request(:get, "http://www.example.com/?a=b&c=d").'+
47
- "\n with(body: \"abcdef\",\n headers: {\'A\'=>\'a\', \'B\'=>\'b\'})." +
47
+ "\n with(\n body: \"abcdef\",\n headers: {\n\t \'A\'=>\'a\',\n\t \'B\'=>\'b\'\n })." +
48
48
  "\n to_return(status: 200, body: \"\", headers: {})"
49
49
  @request_stub = WebMock::RequestStub.from_request_signature(@request_signature)
50
50
  expect(WebMock::StubRequestSnippet.new(@request_stub).to_s).to eq(expected)
@@ -52,7 +52,7 @@ describe WebMock::StubRequestSnippet do
52
52
 
53
53
  it "should not print to_return part if not wanted" do
54
54
  expected = 'stub_request(:get, "http://www.example.com/").'+
55
- "\n with(body: \"abcdef\")"
55
+ "\n with(\n body: \"abcdef\")"
56
56
  stub = WebMock::RequestStub.new(:get, "www.example.com").with(body: "abcdef").to_return(body: "hello")
57
57
  expect(WebMock::StubRequestSnippet.new(stub).to_s(false)).to eq(expected)
58
58
  end
@@ -68,8 +68,11 @@ describe WebMock::StubRequestSnippet do
68
68
  @request_stub = WebMock::RequestStub.from_request_signature(@request_signature)
69
69
  expected = <<-STUB
70
70
  stub_request(:post, "http://www.example.com/").
71
- with(body: {"user"=>{"first_name"=>"Bartosz"}},
72
- headers: {'Content-Type'=>'application/x-www-form-urlencoded'}).
71
+ with(
72
+ body: {"user"=>{"first_name"=>"Bartosz"}},
73
+ headers: {
74
+ \t 'Content-Type'=>'application/x-www-form-urlencoded'
75
+ }).
73
76
  to_return(status: 200, body: \"\", headers: {})
74
77
  STUB
75
78
  expect(WebMock::StubRequestSnippet.new(@request_stub).to_s).to eq(expected.strip)
@@ -82,14 +85,31 @@ stub_request(:post, "http://www.example.com/").
82
85
  @request_stub = WebMock::RequestStub.from_request_signature(@request_signature)
83
86
  expected = <<-STUB
84
87
  stub_request(:post, "http://www.example.com/").
85
- with(body: "#{multipart_form_body}",
86
- headers: {'Content-Type'=>'multipart/form-data; boundary=ABC123'}).
88
+ with(
89
+ body: "#{multipart_form_body}",
90
+ headers: {
91
+ \t 'Content-Type'=>'multipart/form-data; boundary=ABC123'
92
+ }).
87
93
  to_return(status: 200, body: \"\", headers: {})
88
94
  STUB
89
95
  expect(WebMock::StubRequestSnippet.new(@request_stub).to_s).to eq(expected.strip)
90
96
  end
91
- end
92
97
 
98
+ it "should print stub request snippet with valid JSON body when request header contains 'Accept'=>'application/json' " do
99
+ @request_signature = WebMock::RequestSignature.new(:post, "www.example.com",
100
+ headers: {'Accept' => 'application/json'})
101
+ @request_stub = WebMock::RequestStub.from_request_signature(@request_signature)
102
+ expected = <<-STUB
103
+ stub_request(:post, "http://www.example.com/").
104
+ with(
105
+ headers: {
106
+ \t 'Accept'=>'application/json'
107
+ }).
108
+ to_return(status: 200, body: \"{}\", headers: {})
109
+ STUB
110
+ expect(WebMock::StubRequestSnippet.new(@request_stub).to_s).to eq(expected.strip)
111
+ end
112
+ end
93
113
 
94
114
  end
95
115
  end