webmock 1.8.6 → 3.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/CI.yml +37 -0
  3. data/.gitignore +6 -0
  4. data/CHANGELOG.md +1198 -0
  5. data/Gemfile +3 -15
  6. data/README.md +761 -305
  7. data/Rakefile +13 -40
  8. data/lib/webmock/api.rb +63 -17
  9. data/lib/webmock/callback_registry.rb +1 -1
  10. data/lib/webmock/config.rb +8 -0
  11. data/lib/webmock/cucumber.rb +2 -0
  12. data/lib/webmock/errors.rb +8 -24
  13. data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +216 -0
  14. data/lib/webmock/http_lib_adapters/curb_adapter.rb +148 -84
  15. data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +224 -4
  16. data/lib/webmock/http_lib_adapters/excon_adapter.rb +104 -34
  17. data/lib/webmock/http_lib_adapters/http_rb/client.rb +17 -0
  18. data/lib/webmock/http_lib_adapters/http_rb/request.rb +16 -0
  19. data/lib/webmock/http_lib_adapters/http_rb/response.rb +64 -0
  20. data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +29 -0
  21. data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +68 -0
  22. data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +37 -0
  23. data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +152 -86
  24. data/lib/webmock/http_lib_adapters/manticore_adapter.rb +145 -0
  25. data/lib/webmock/http_lib_adapters/net_http.rb +155 -46
  26. data/lib/webmock/http_lib_adapters/net_http_response.rb +1 -1
  27. data/lib/webmock/http_lib_adapters/patron_adapter.rb +16 -15
  28. data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +76 -82
  29. data/lib/webmock/matchers/any_arg_matcher.rb +13 -0
  30. data/lib/webmock/matchers/hash_argument_matcher.rb +21 -0
  31. data/lib/webmock/matchers/hash_excluding_matcher.rb +15 -0
  32. data/lib/webmock/matchers/hash_including_matcher.rb +4 -12
  33. data/lib/webmock/minitest.rb +29 -3
  34. data/lib/webmock/rack_response.rb +14 -7
  35. data/lib/webmock/request_body_diff.rb +64 -0
  36. data/lib/webmock/request_execution_verifier.rb +38 -17
  37. data/lib/webmock/request_pattern.rb +158 -38
  38. data/lib/webmock/request_registry.rb +3 -3
  39. data/lib/webmock/request_signature.rb +7 -3
  40. data/lib/webmock/request_signature_snippet.rb +61 -0
  41. data/lib/webmock/request_stub.rb +9 -6
  42. data/lib/webmock/response.rb +30 -15
  43. data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +38 -2
  44. data/lib/webmock/rspec/matchers/webmock_matcher.rb +23 -2
  45. data/lib/webmock/rspec/matchers.rb +0 -1
  46. data/lib/webmock/rspec.rb +11 -2
  47. data/lib/webmock/stub_registry.rb +31 -10
  48. data/lib/webmock/stub_request_snippet.rb +14 -6
  49. data/lib/webmock/test_unit.rb +4 -4
  50. data/lib/webmock/util/hash_counter.rb +20 -6
  51. data/lib/webmock/util/hash_keys_stringifier.rb +5 -3
  52. data/lib/webmock/util/hash_validator.rb +17 -0
  53. data/lib/webmock/util/headers.rb +23 -2
  54. data/lib/webmock/util/json.rb +20 -7
  55. data/lib/webmock/util/query_mapper.rb +281 -0
  56. data/lib/webmock/util/uri.rb +29 -19
  57. data/lib/webmock/util/values_stringifier.rb +20 -0
  58. data/lib/webmock/util/version_checker.rb +40 -2
  59. data/lib/webmock/version.rb +1 -1
  60. data/lib/webmock/webmock.rb +56 -17
  61. data/lib/webmock.rb +56 -46
  62. data/minitest/test_helper.rb +8 -3
  63. data/minitest/test_webmock.rb +4 -1
  64. data/minitest/webmock_spec.rb +16 -6
  65. data/spec/acceptance/async_http_client/async_http_client_spec.rb +375 -0
  66. data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
  67. data/spec/acceptance/curb/curb_spec.rb +227 -68
  68. data/spec/acceptance/curb/curb_spec_helper.rb +11 -8
  69. data/spec/acceptance/em_http_request/em_http_request_spec.rb +322 -28
  70. data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +15 -10
  71. data/spec/acceptance/excon/excon_spec.rb +66 -4
  72. data/spec/acceptance/excon/excon_spec_helper.rb +21 -7
  73. data/spec/acceptance/http_rb/http_rb_spec.rb +93 -0
  74. data/spec/acceptance/http_rb/http_rb_spec_helper.rb +54 -0
  75. data/spec/acceptance/httpclient/httpclient_spec.rb +152 -11
  76. data/spec/acceptance/httpclient/httpclient_spec_helper.rb +25 -16
  77. data/spec/acceptance/manticore/manticore_spec.rb +107 -0
  78. data/spec/acceptance/manticore/manticore_spec_helper.rb +35 -0
  79. data/spec/acceptance/net_http/net_http_shared.rb +52 -24
  80. data/spec/acceptance/net_http/net_http_spec.rb +164 -50
  81. data/spec/acceptance/net_http/net_http_spec_helper.rb +19 -10
  82. data/spec/acceptance/net_http/real_net_http_spec.rb +1 -1
  83. data/spec/acceptance/patron/patron_spec.rb +29 -40
  84. data/spec/acceptance/patron/patron_spec_helper.rb +15 -11
  85. data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +229 -58
  86. data/spec/acceptance/shared/callbacks.rb +32 -30
  87. data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +20 -5
  88. data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +14 -14
  89. data/spec/acceptance/shared/precedence_of_stubs.rb +6 -6
  90. data/spec/acceptance/shared/request_expectations.rb +560 -296
  91. data/spec/acceptance/shared/returning_declared_responses.rb +180 -138
  92. data/spec/acceptance/shared/stubbing_requests.rb +385 -154
  93. data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +78 -17
  94. data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +19 -15
  95. data/spec/acceptance/webmock_shared.rb +2 -2
  96. data/spec/fixtures/test.txt +1 -0
  97. data/spec/quality_spec.rb +27 -3
  98. data/spec/spec_helper.rb +11 -20
  99. data/spec/support/failures.rb +9 -0
  100. data/spec/support/my_rack_app.rb +8 -3
  101. data/spec/support/network_connection.rb +7 -13
  102. data/spec/support/webmock_server.rb +8 -3
  103. data/spec/unit/api_spec.rb +175 -0
  104. data/spec/unit/errors_spec.rb +116 -19
  105. data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +1 -1
  106. data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +2 -2
  107. data/spec/unit/matchers/hash_excluding_matcher_spec.rb +61 -0
  108. data/spec/unit/matchers/hash_including_matcher_spec.rb +87 -0
  109. data/spec/unit/rack_response_spec.rb +54 -16
  110. data/spec/unit/request_body_diff_spec.rb +90 -0
  111. data/spec/unit/request_execution_verifier_spec.rb +147 -39
  112. data/spec/unit/request_pattern_spec.rb +462 -198
  113. data/spec/unit/request_registry_spec.rb +29 -9
  114. data/spec/unit/request_signature_snippet_spec.rb +89 -0
  115. data/spec/unit/request_signature_spec.rb +91 -49
  116. data/spec/unit/request_stub_spec.rb +71 -70
  117. data/spec/unit/response_spec.rb +100 -81
  118. data/spec/unit/stub_registry_spec.rb +37 -20
  119. data/spec/unit/stub_request_snippet_spec.rb +51 -31
  120. data/spec/unit/util/hash_counter_spec.rb +6 -6
  121. data/spec/unit/util/hash_keys_stringifier_spec.rb +4 -4
  122. data/spec/unit/util/headers_spec.rb +4 -4
  123. data/spec/unit/util/json_spec.rb +29 -3
  124. data/spec/unit/util/query_mapper_spec.rb +157 -0
  125. data/spec/unit/util/uri_spec.rb +150 -36
  126. data/spec/unit/util/version_checker_spec.rb +15 -9
  127. data/spec/unit/webmock_spec.rb +57 -4
  128. data/test/http_request.rb +3 -3
  129. data/test/shared_test.rb +45 -13
  130. data/test/test_helper.rb +1 -1
  131. data/test/test_webmock.rb +6 -0
  132. data/webmock.gemspec +30 -11
  133. metadata +308 -199
  134. data/.rvmrc +0 -1
  135. data/.travis.yml +0 -11
  136. data/Guardfile +0 -24
  137. data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_0_x.rb +0 -151
  138. data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_1_x.rb +0 -210
data/README.md CHANGED
@@ -1,5 +1,11 @@
1
- WebMock [![Build Status](https://secure.travis-ci.org/bblimke/webmock.png)](http://travis-ci.org/bblimke/webmock) [![Dependency Status](https://gemnasium.com/bblimke/webmock.png)](http://gemnasium.com/bblimke/webmock)
1
+ WebMock
2
2
  =======
3
+ [![Gem Version](https://badge.fury.io/rb/webmock.svg)](http://badge.fury.io/rb/webmock)
4
+ [![Build Status](https://github.com/bblimke/webmock/workflows/CI/badge.svg?branch=master)](https://github.com/bblimke/webmock/actions)
5
+ [![Code Climate](https://codeclimate.com/github/bblimke/webmock/badges/gpa.svg)](https://codeclimate.com/github/bblimke/webmock)
6
+ [![Mentioned in Awesome Ruby](https://awesome.re/mentioned-badge.svg)](https://github.com/markets/awesome-ruby)
7
+ [![Inline docs](http://inch-ci.org/github/bblimke/webmock.svg?branch=master)](http://inch-ci.org/github/bblimke/webmock)
8
+ [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=webmock&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=webmock&package-manager=bundler&version-scheme=semver)
3
9
 
4
10
  Library for stubbing and setting expectations on HTTP requests in Ruby.
5
11
 
@@ -12,35 +18,48 @@ Features
12
18
  * Smart matching of the same URIs in different representations (also encoded and non encoded forms)
13
19
  * Smart matching of the same headers in different representations.
14
20
  * Support for Test::Unit
15
- * Support for RSpec 1.x and RSpec 2.x
21
+ * Support for RSpec
16
22
  * Support for MiniTest
17
23
 
18
24
  Supported HTTP libraries
19
25
  ------------------------
20
26
 
21
- * Net::HTTP and libraries based on Net::HTTP (i.e RightHttpConnection, REST Client, HTTParty)
22
- * HTTPClient
23
- * Patron
24
- * EM-HTTP-Request
25
- * Curb (currently only Curb::Easy)
26
- * Typhoeus (currently only Typhoeus::Hydra)
27
- * Excon
27
+ * [Async::HTTP::Client](https://github.com/socketry/async-http)
28
+ * [Curb](https://github.com/taf2/curb) (currently only Curb::Easy)
29
+ * [EM-HTTP-Request](https://github.com/igrigorik/em-http-request)
30
+ * [Excon](https://github.com/excon/excon)
31
+ * [HTTPClient](https://github.com/nahi/httpclient)
32
+ * [HTTP Gem (also known as http.rb)](https://github.com/httprb/http)
33
+ * [httpx](https://honeyryderchuck.gitlab.io/httpx/wiki/Webmock-Adapter)
34
+ * [Manticore](https://github.com/cheald/manticore)
35
+ * [Net::HTTP](https://ruby-doc.org/stdlib-2.7.0/libdoc/net/http/rdoc/Net/HTTP.html) and other libraries based on Net::HTTP, e.g.:
36
+ * [HTTParty](https://github.com/jnunemaker/httparty)
37
+ * [REST Client](https://github.com/rest-client/rest-client)
38
+ * [Patron](https://github.com/toland/patron)
39
+ * [Typhoeus](https://github.com/typhoeus/typhoeus) (currently only Typhoeus::Hydra)
28
40
 
29
41
  Supported Ruby Interpreters
30
42
  ---------------------------
31
43
 
32
- * MRI 1.8.6
33
- * MRI 1.8.7
34
- * MRI 1.9.1
35
- * MRI 1.9.2
36
- * MRI 1.9.3
37
- * REE 1.8.7
44
+ * MRI 2.5
45
+ * MRI 2.6
46
+ * MRI 2.7
38
47
  * JRuby
39
48
  * Rubinius
40
49
 
41
- ##Installation
50
+ ## Installation
42
51
 
52
+ ```bash
43
53
  gem install webmock
54
+ ```
55
+ or alternatively:
56
+
57
+ ```ruby
58
+ # add to your Gemfile
59
+ group :test do
60
+ gem "webmock"
61
+ end
62
+ ```
44
63
 
45
64
  ### or to install the latest development version from github master
46
65
 
@@ -48,308 +67,514 @@ Supported Ruby Interpreters
48
67
  cd webmock
49
68
  rake install
50
69
 
51
- ### Test::Unit
52
-
53
- Add the following code to `test/test_helper.rb`
70
+ ## Upgrading from v1.x to v2.x
54
71
 
55
- require 'webmock/test_unit'
72
+ WebMock 2.x has changed somewhat since version 1.x. Changes are listed in [CHANGELOG.md](CHANGELOG.md)
56
73
 
57
- ### RSpec
74
+ ### Cucumber
58
75
 
59
- Add the following code to `spec/spec_helper`:
76
+ Create a file `features/support/webmock.rb` with the following contents:
60
77
 
61
- require 'webmock/rspec'
78
+ ```ruby
79
+ require 'webmock/cucumber'
80
+ ```
62
81
 
63
82
  ### MiniTest
64
83
 
65
84
  Add the following code to `test/test_helper`:
66
85
 
67
- require 'webmock/minitest'
86
+ ```ruby
87
+ require 'webmock/minitest'
88
+ ```
68
89
 
69
- ### Cucumber
90
+ ### RSpec
91
+
92
+ Add the following code to `spec/spec_helper`:
93
+
94
+ ```ruby
95
+ require 'webmock/rspec'
96
+ ```
97
+
98
+ ### Test::Unit
70
99
 
71
- Add the following code to `features/support/env.rb`
100
+ Add the following code to `test/test_helper.rb`
72
101
 
73
- require 'webmock/cucumber'
102
+ ```ruby
103
+ require 'webmock/test_unit'
104
+ ```
74
105
 
75
106
  ### Outside a test framework
76
107
 
77
108
  You can also use WebMock outside a test framework:
78
109
 
79
- require 'webmock'
80
- include WebMock::API
81
-
82
- ## Examples
110
+ ```ruby
111
+ require 'webmock'
112
+ include WebMock::API
83
113
 
114
+ WebMock.enable!
115
+ ```
84
116
 
117
+ # Examples
85
118
 
86
119
  ## Stubbing
87
120
 
88
-
89
121
  ### Stubbed request based on uri only and with the default response
90
122
 
91
- stub_request(:any, "www.example.com")
123
+ ```ruby
124
+ stub_request(:any, "www.example.com")
92
125
 
93
- Net::HTTP.get("www.example.com", "/") # ===> Success
126
+ Net::HTTP.get("www.example.com", "/") # ===> Success
127
+ ```
94
128
 
95
129
  ### Stubbing requests based on method, uri, body and headers
96
130
 
97
- stub_request(:post, "www.example.com").with(:body => "abc", :headers => { 'Content-Length' => 3 })
131
+ ```ruby
132
+ stub_request(:post, "www.example.com").
133
+ with(body: "abc", headers: { 'Content-Length' => 3 })
134
+
135
+ uri = URI.parse("http://www.example.com/")
136
+ req = Net::HTTP::Post.new(uri.path)
137
+ req['Content-Length'] = 3
98
138
 
99
- uri = URI.parse("http://www.example.com/")
100
- req = Net::HTTP::Post.new(uri.path)
101
- req['Content-Length'] = 3
102
- res = Net::HTTP.start(uri.host, uri.port) {|http|
103
- http.request(req, "abc")
104
- } # ===> Success
139
+ res = Net::HTTP.start(uri.host, uri.port) do |http|
140
+ http.request(req, "abc")
141
+ end # ===> Success
142
+ ```
105
143
 
106
144
  ### Matching request body and headers against regular expressions
107
145
 
108
- stub_request(:post, "www.example.com").
109
- with(:body => /^.*world$/, :headers => {"Content-Type" => /image\/.+/}).to_return(:body => "abc")
146
+ ```ruby
147
+ stub_request(:post, "www.example.com").
148
+ with(body: /world$/, headers: {"Content-Type" => /image\/.+/}).
149
+ to_return(body: "abc")
150
+
151
+ uri = URI.parse('http://www.example.com/')
152
+ req = Net::HTTP::Post.new(uri.path)
153
+ req['Content-Type'] = 'image/png'
110
154
 
111
- uri = URI.parse('http://www.example.com/')
112
- req = Net::HTTP::Post.new(uri.path)
113
- req['Content-Type'] = 'image/png'
114
- res = Net::HTTP.start(uri.host, uri.port) {|http|
115
- http.request(req, 'hello world')
116
- } # ===> Success
155
+ res = Net::HTTP.start(uri.host, uri.port) do |http|
156
+ http.request(req, 'hello world')
157
+ end # ===> Success
158
+ ```
117
159
 
118
160
  ### Matching request body against a hash. Body can be URL-Encoded, JSON or XML.
119
161
 
120
- stub_http_request(:post, "www.example.com").
121
- with(:body => {:data => {:a => '1', :b => 'five'}})
162
+ ```ruby
163
+ stub_request(:post, "www.example.com").
164
+ with(body: {data: {a: '1', b: 'five'}})
122
165
 
123
- RestClient.post('www.example.com', "data[a]=1&data[b]=five",
124
- :content_type => 'application/x-www-form-urlencoded') # ===> Success
166
+ RestClient.post('www.example.com', "data[a]=1&data[b]=five",
167
+ content_type: 'application/x-www-form-urlencoded') # ===> Success
125
168
 
126
- RestClient.post('www.example.com', '{"data":{"a":"1","b":"five"}}',
127
- :content_type => 'application/json') # ===> Success
169
+ RestClient.post('www.example.com', '{"data":{"a":"1","b":"five"}}',
170
+ content_type: 'application/json') # ===> Success
128
171
 
129
- RestClient.post('www.example.com', '<data a="1" b="five" />',
130
- :content_type => 'application/xml' ) # ===> Success
172
+ RestClient.post('www.example.com', '<data a="1" b="five" />',
173
+ content_type: 'application/xml') # ===> Success
174
+ ```
131
175
 
132
176
  ### Matching request body against partial hash.
133
177
 
134
- stub_http_request(:post, "www.example.com").
135
- with(:body => hash_including({:data => {:a => '1', :b => 'five'}}))
178
+ ```ruby
179
+ stub_request(:post, "www.example.com").
180
+ with(body: hash_including({data: {a: '1', b: 'five'}}))
136
181
 
137
- RestClient.post('www.example.com', "data[a]=1&data[b]=five&x=1",
138
- :content_type => 'application/x-www-form-urlencoded') # ===> Success
182
+ RestClient.post('www.example.com', "data[a]=1&data[b]=five&x=1",
183
+ :content_type => 'application/x-www-form-urlencoded') # ===> Success
184
+ ```
139
185
 
140
186
  ### Matching custom request headers
141
187
 
142
- stub_request(:any, "www.example.com").with(:headers=>{ 'Header-Name' => 'Header-Value' })
188
+ ```ruby
189
+ stub_request(:any, "www.example.com").
190
+ with(headers:{ 'Header-Name' => 'Header-Value' })
143
191
 
144
- uri = URI.parse('http://www.example.com/')
145
- req = Net::HTTP::Post.new(uri.path)
146
- req['Header-Name'] = 'Header-Value'
147
- res = Net::HTTP.start(uri.host, uri.port) {|http|
148
- http.request(req, 'abc')
149
- } # ===> Success
192
+ uri = URI.parse('http://www.example.com/')
193
+ req = Net::HTTP::Post.new(uri.path)
194
+ req['Header-Name'] = 'Header-Value'
195
+
196
+ res = Net::HTTP.start(uri.host, uri.port) do |http|
197
+ http.request(req, 'abc')
198
+ end # ===> Success
199
+ ```
150
200
 
151
201
  ### Matching multiple headers with the same name
152
202
 
153
- stub_http_request(:get, 'www.example.com').with(:headers => {'Accept' => ['image/jpeg', 'image/png'] })
203
+ ```ruby
204
+ stub_request(:get, 'www.example.com').
205
+ with(headers: {'Accept' => ['image/jpeg', 'image/png'] })
154
206
 
155
- req = Net::HTTP::Get.new("/")
156
- req['Accept'] = ['image/png']
157
- req.add_field('Accept', 'image/jpeg')
158
- Net::HTTP.start("www.example.com") {|http| http.request(req) } # ===> Success
207
+ req = Net::HTTP::Get.new("/")
208
+ req['Accept'] = ['image/png']
209
+ req.add_field('Accept', 'image/jpeg')
210
+ Net::HTTP.start("www.example.com") {|http| http.request(req) } # ===> Success
211
+ ```
159
212
 
160
213
  ### Matching requests against provided block
161
214
 
162
- stub_request(:post, "www.example.com").with { |request| request.body == "abc" }
163
- RestClient.post('www.example.com', 'abc') # ===> Success
215
+ ```ruby
216
+ stub_request(:post, "www.example.com").with { |request| request.body == "abc" }
217
+ RestClient.post('www.example.com', 'abc') # ===> Success
218
+ ```
219
+
220
+ ### Request with basic authentication header
164
221
 
165
- ### Request with basic authentication
222
+ ```ruby
223
+ stub_request(:get, "www.example.com").with(basic_auth: ['user', 'pass'])
224
+ # or
225
+ # stub_request(:get, "www.example.com").
226
+ # with(headers: {'Authorization' => "Basic #{ Base64.strict_encode64('user:pass').chomp}"})
166
227
 
167
- stub_request(:get, "user:pass@www.example.com")
228
+ Net::HTTP.start('www.example.com') do |http|
229
+ req = Net::HTTP::Get.new('/')
230
+ req.basic_auth 'user', 'pass'
231
+ http.request(req)
232
+ end # ===> Success
233
+ ```
168
234
 
169
- Net::HTTP.start('www.example.com') {|http|
170
- req = Net::HTTP::Get.new('/')
171
- req.basic_auth 'user', 'pass'
172
- http.request(req)
173
- } # ===> Success
235
+ ##### Important! Since version 2.0.0, WebMock does not match credentials provided in Authorization header and credentials provided in the userinfo of a url. I.e. `stub_request(:get, "user:pass@www.example.com")` does not match a request with credentials provided in the Authorization header.
236
+
237
+ ### Request with basic authentication in the url
238
+
239
+ ```ruby
240
+ stub_request(:get, "user:pass@www.example.com")
241
+
242
+ RestClient.get('user:pass@www.example.com') # ===> Success
243
+ ```
174
244
 
175
245
  ### Matching uris using regular expressions
176
246
 
177
- stub_request(:any, /.*example.*/)
247
+ ```ruby
248
+ stub_request(:any, /example/)
249
+
250
+ Net::HTTP.get('www.example.com', '/') # ===> Success
251
+ ```
252
+
253
+ ### Matching uris using lambda
254
+
255
+ ```ruby
256
+ stub_request(:any, ->(uri) { true })
257
+ ```
258
+
259
+ ### Matching uris using RFC 6570 - Basic Example
260
+
261
+ ```ruby
262
+ uri_template = Addressable::Template.new "www.example.com/{id}/"
263
+ stub_request(:any, uri_template)
264
+
265
+ Net::HTTP.get('www.example.com', '/webmock/') # ===> Success
266
+ ```
267
+
268
+ ### Matching uris using RFC 6570 - Advanced Example
269
+
270
+ ```ruby
271
+ uri_template =
272
+ Addressable::Template.new "www.example.com/thing/{id}.json{?x,y,z}{&other*}"
273
+ stub_request(:any, uri_template)
178
274
 
179
- Net::HTTP.get('www.example.com', '/') # ===> Success
275
+ Net::HTTP.get('www.example.com',
276
+ '/thing/5.json?x=1&y=2&z=3&anyParam=4') # ===> Success
277
+ ```
180
278
 
181
279
  ### Matching query params using hash
182
280
 
183
- stub_http_request(:get, "www.example.com").with(:query => {"a" => ["b", "c"]})
281
+ ```ruby
282
+ stub_request(:get, "www.example.com").with(query: {"a" => ["b", "c"]})
184
283
 
185
- RestClient.get("http://www.example.com/?a[]=b&a[]=c") # ===> Success
284
+ RestClient.get("http://www.example.com/?a[]=b&a[]=c") # ===> Success
285
+ ```
186
286
 
187
287
  ### Matching partial query params using hash
188
288
 
189
- stub_http_request(:get, "www.example.com").with(:query => hash_including({"a" => ["b", "c"]}))
289
+ ```ruby
290
+ stub_request(:get, "www.example.com").
291
+ with(query: hash_including({"a" => ["b", "c"]}))
190
292
 
191
- RestClient.get("http://www.example.com/?a[]=b&a[]=c&x=1") # ===> Success
293
+ RestClient.get("http://www.example.com/?a[]=b&a[]=c&x=1") # ===> Success
294
+ ```
295
+
296
+ ### Matching partial query params using hash_excluding
297
+
298
+ ```ruby
299
+ stub_request(:get, "www.example.com").
300
+ with(query: hash_excluding({"a" => "b"}))
301
+
302
+ RestClient.get("http://www.example.com/?a=b") # ===> Failure
303
+ RestClient.get("http://www.example.com/?a=c") # ===> Success
304
+ ```
192
305
 
193
306
  ### Stubbing with custom response
194
307
 
195
- stub_request(:any, "www.example.com").to_return(:body => "abc", :status => 200, :headers => { 'Content-Length' => 3 } )
308
+ ```ruby
309
+ stub_request(:any, "www.example.com").
310
+ to_return(body: "abc", status: 200,
311
+ headers: { 'Content-Length' => 3 })
196
312
 
197
- Net::HTTP.get("www.example.com", '/') # ===> "abc"
313
+ Net::HTTP.get("www.example.com", '/') # ===> "abc"
314
+ ```
315
+
316
+ Set appropriate Content-Type for HTTParty's `parsed_response`.
317
+
318
+ ```ruby
319
+ stub_request(:any, "www.example.com").to_return body: '{}', headers: {content_type: 'application/json'}
320
+ ```
198
321
 
199
322
  ### Response with body specified as IO object
200
323
 
201
- File.open('/tmp/response_body.txt', 'w') { |f| f.puts 'abc' }
324
+ ```ruby
325
+ File.open('/tmp/response_body.txt', 'w') { |f| f.puts 'abc' }
202
326
 
203
- stub_request(:any, "www.example.com").to_return(:body => File.new('/tmp/response_body.txt'), :status => 200)
327
+ stub_request(:any, "www.example.com").
328
+ to_return(body: File.new('/tmp/response_body.txt'), status: 200)
204
329
 
205
- Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
330
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
331
+ ```
206
332
 
207
333
  ### Response with custom status message
208
334
 
209
- stub_request(:any, "www.example.com").to_return(:status => [500, "Internal Server Error"])
335
+ ```ruby
336
+ stub_request(:any, "www.example.com").
337
+ to_return(status: [500, "Internal Server Error"])
210
338
 
211
- req = Net::HTTP::Get.new("/")
212
- Net::HTTP.start("www.example.com") { |http| http.request(req) }.message # ===> "Internal Server Error"
339
+ req = Net::HTTP::Get.new("/")
340
+ Net::HTTP.start("www.example.com") { |http| http.request(req) }.
341
+ message # ===> "Internal Server Error"
342
+ ```
213
343
 
214
344
  ### Replaying raw responses recorded with `curl -is`
215
345
 
216
- `curl -is www.example.com > /tmp/example_curl_-is_output.txt`
217
- raw_response_file = File.new("/tmp/example_curl_-is_output.txt")
346
+ ```
347
+ curl -is www.example.com > /tmp/example_curl_-is_output.txt
348
+ ```
349
+
350
+ ```ruby
351
+ raw_response_file = File.new("/tmp/example_curl_-is_output.txt")
352
+ ```
218
353
 
219
354
  from file
220
355
 
221
- stub_request(:get, "www.example.com").to_return(raw_response_file)
356
+ ```ruby
357
+ stub_request(:get, "www.example.com").to_return(raw_response_file)
358
+ ```
222
359
 
223
360
  or string
224
361
 
225
- stub_request(:get, "www.example.com").to_return(raw_response_file.read)
362
+ ```ruby
363
+ stub_request(:get, "www.example.com").to_return(raw_response_file.read)
364
+ ```
226
365
 
227
366
  ### Responses dynamically evaluated from block
228
367
 
229
- stub_request(:any, 'www.example.net').
230
- to_return { |request| {:body => request.body} }
368
+ ```ruby
369
+ stub_request(:any, 'www.example.net').
370
+ to_return { |request| {body: request.body} }
231
371
 
232
- RestClient.post('www.example.net', 'abc') # ===> "abc\n"
372
+ RestClient.post('www.example.net', 'abc') # ===> "abc\n"
373
+ ```
233
374
 
234
375
  ### Responses dynamically evaluated from lambda
235
376
 
236
- stub_request(:any, 'www.example.net').
237
- to_return(lambda { |request| {:body => request.body} })
377
+ ```ruby
378
+ stub_request(:any, 'www.example.net').
379
+ to_return(lambda { |request| {body: request.body} })
238
380
 
239
- RestClient.post('www.example.net', 'abc') # ===> "abc\n"
381
+ RestClient.post('www.example.net', 'abc') # ===> "abc\n"
382
+ ```
240
383
 
241
384
  ### Dynamically evaluated raw responses recorded with `curl -is`
242
385
 
243
386
  `curl -is www.example.com > /tmp/www.example.com.txt`
244
- stub_request(:get, "www.example.com").to_return(lambda { |request| File.new("/tmp/#{request.uri.host.to_s}.txt" }))
387
+ ```ruby
388
+ stub_request(:get, "www.example.com").
389
+ to_return(lambda { |request| File.new("/tmp/#{request.uri.host.to_s}.txt") })
390
+ ```
245
391
 
246
392
  ### Responses with dynamically evaluated parts
247
393
 
248
- stub_request(:any, 'www.example.net').
249
- to_return(:body => lambda { |request| request.body })
394
+ ```ruby
395
+ stub_request(:any, 'www.example.net').
396
+ to_return(body: lambda { |request| request.body })
250
397
 
251
- RestClient.post('www.example.net', 'abc') # ===> "abc\n"
398
+ RestClient.post('www.example.net', 'abc') # ===> "abc\n"
399
+ ```
252
400
 
253
401
  ### Rack responses
254
402
 
255
- class MyRackApp
256
- def self.call(env)
257
- [200, {}, ["Hello"]]
258
- end
259
- end
403
+ ```ruby
404
+ class MyRackApp
405
+ def self.call(env)
406
+ [200, {}, ["Hello"]]
407
+ end
408
+ end
260
409
 
261
- stub_request(:get, "www.example.com").to_rack(MyRackApp)
410
+ stub_request(:get, "www.example.com").to_rack(MyRackApp)
262
411
 
263
- RestClient.post('www.example.com') # ===> "Hello"
412
+ RestClient.post('www.example.com') # ===> "Hello"
413
+ ```
264
414
 
265
415
  ### Raising errors
266
416
 
267
417
  #### Exception declared by class
268
418
 
269
- stub_request(:any, 'www.example.net').to_raise(StandardError)
419
+ ```ruby
420
+ stub_request(:any, 'www.example.net').to_raise(StandardError)
270
421
 
271
- RestClient.post('www.example.net', 'abc') # ===> StandardError
422
+ RestClient.post('www.example.net', 'abc') # ===> StandardError
423
+ ```
272
424
 
273
425
  #### or by exception instance
274
426
 
275
- stub_request(:any, 'www.example.net').to_raise(StandardError.new("some error"))
427
+ ```ruby
428
+ stub_request(:any, 'www.example.net').to_raise(StandardError.new("some error"))
429
+ ```
276
430
 
277
431
  #### or by string
278
432
 
279
- stub_request(:any, 'www.example.net').to_raise("some error")
433
+ ```ruby
434
+ stub_request(:any, 'www.example.net').to_raise("some error")
435
+ ```
280
436
 
281
437
  ### Raising timeout errors
282
438
 
283
- stub_request(:any, 'www.example.net').to_timeout
439
+ ```ruby
440
+ stub_request(:any, 'www.example.net').to_timeout
284
441
 
285
- RestClient.post('www.example.net', 'abc') # ===> RestClient::RequestTimeout
442
+ RestClient.post('www.example.net', 'abc') # ===> RestClient::RequestTimeout
443
+ ```
286
444
 
287
445
  ### Multiple responses for repeated requests
288
446
 
289
- stub_request(:get, "www.example.com").to_return({:body => "abc"}, {:body => "def"})
290
- Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
291
- Net::HTTP.get('www.example.com', '/') # ===> "def\n"
447
+ ```ruby
448
+ stub_request(:get, "www.example.com").
449
+ to_return({body: "abc"}, {body: "def"})
450
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
451
+ Net::HTTP.get('www.example.com', '/') # ===> "def\n"
292
452
 
293
- #after all responses are used the last response will be returned infinitely
453
+ #after all responses are used the last response will be returned infinitely
294
454
 
295
- Net::HTTP.get('www.example.com', '/') # ===> "def\n"
455
+ Net::HTTP.get('www.example.com', '/') # ===> "def\n"
456
+ ```
296
457
 
297
458
  ### Multiple responses using chained `to_return()`, `to_raise()` or `to_timeout` declarations
298
459
 
299
- stub_request(:get, "www.example.com").
300
- to_return({:body => "abc"}).then. #then() is just a syntactic sugar
301
- to_return({:body => "def"}).then.
302
- to_raise(MyException)
303
- Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
304
- Net::HTTP.get('www.example.com', '/') # ===> "def\n"
305
- Net::HTTP.get('www.example.com', '/') # ===> MyException raised
460
+ ```ruby
461
+ stub_request(:get, "www.example.com").
462
+ to_return({body: "abc"}).then. #then() is just a syntactic sugar
463
+ to_return({body: "def"}).then.
464
+ to_raise(MyException)
465
+
466
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
467
+ Net::HTTP.get('www.example.com', '/') # ===> "def\n"
468
+ Net::HTTP.get('www.example.com', '/') # ===> MyException raised
469
+ ```
306
470
 
307
471
  ### Specifying number of times given response should be returned
308
472
 
309
- stub_request(:get, "www.example.com").
310
- to_return({:body => "abc"}).times(2).then.
311
- to_return({:body => "def"})
473
+ ```ruby
474
+ stub_request(:get, "www.example.com").
475
+ to_return({body: "abc"}).times(2).then.
476
+ to_return({body: "def"})
477
+
478
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
479
+ Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
480
+ Net::HTTP.get('www.example.com', '/') # ===> "def\n"
481
+ ```
312
482
 
313
- Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
314
- Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
315
- Net::HTTP.get('www.example.com', '/') # ===> "def\n"
483
+ ### Removing unused stubs
316
484
 
485
+ ```ruby
486
+ stub_get = stub_request(:get, "www.example.com")
487
+ remove_request_stub(stub_get)
488
+ ```
317
489
 
318
490
  ### Real requests to network can be allowed or disabled
319
491
 
320
- WebMock.allow_net_connect!
492
+ ```ruby
493
+ WebMock.allow_net_connect!
321
494
 
322
- stub_request(:any, "www.example.com").to_return(:body => "abc")
495
+ stub_request(:any, "www.example.com").to_return(body: "abc")
323
496
 
324
- Net::HTTP.get('www.example.com', '/') # ===> "abc"
497
+ Net::HTTP.get('www.example.com', '/') # ===> "abc"
325
498
 
326
- Net::HTTP.get('www.something.com', '/') # ===> /.+Something.+/
499
+ Net::HTTP.get('www.something.com', '/') # ===> /.+Something.+/
327
500
 
328
- WebMock.disable_net_connect!
501
+ WebMock.disable_net_connect!
329
502
 
330
- Net::HTTP.get('www.something.com', '/') # ===> Failure
503
+ Net::HTTP.get('www.something.com', '/') # ===> Failure
504
+ ```
331
505
 
332
506
  ### External requests can be disabled while allowing localhost
333
507
 
334
- WebMock.disable_net_connect!(:allow_localhost => true)
508
+ ```ruby
509
+ WebMock.disable_net_connect!(allow_localhost: true)
510
+
511
+ Net::HTTP.get('www.something.com', '/') # ===> Failure
512
+
513
+ Net::HTTP.get('localhost:9887', '/') # ===> Allowed. Perhaps to Selenium?
514
+ ```
335
515
 
336
- Net::HTTP.get('www.something.com', '/') # ===> Failure
516
+ ### External requests can be disabled while allowing specific requests
337
517
 
338
- Net::HTTP.get('localhost:9887', '/') # ===> Allowed. Perhaps to Selenium?
518
+ Allowed requests can be specified in a number of ways.
339
519
 
340
- ### External requests can be disabled while allowing any hostname or port or parts thereof
520
+ With a `String` specifying a host name:
341
521
 
342
- WebMock.disable_net_connect!(:allow => "www.example.org:8080")
522
+ ```ruby
523
+ WebMock.disable_net_connect!(allow: 'www.example.org')
343
524
 
344
- RestClient.get('www.something.com', '/') # ===> Failure
525
+ RestClient.get('www.something.com', '/') # ===> Failure
526
+ RestClient.get('www.example.org', '/') # ===> Allowed
527
+ RestClient.get('www.example.org:8080', '/') # ===> Allowed
528
+ ```
345
529
 
346
- RestClient.get('www.example.org', '/') # ===> Failure.
530
+ With a `String` specifying a host name and a port:
347
531
 
348
- RestClient.get('www.example.org:8080', '/') # ===> Allowed
532
+ ```ruby
533
+ WebMock.disable_net_connect!(allow: 'www.example.org:8080')
349
534
 
350
- WebMock.disable_net_connect!(:allow => /ample.org/)
535
+ RestClient.get('www.something.com', '/') # ===> Failure
536
+ RestClient.get('www.example.org', '/') # ===> Failure
537
+ RestClient.get('www.example.org:8080', '/') # ===> Allowed
538
+ ```
351
539
 
352
- RestClient.get('www.example.org', '/') # ===> Allowed
540
+ With a `Regexp` matching the URI:
541
+
542
+ ```ruby
543
+ WebMock.disable_net_connect!(allow: %r{ample.org/foo})
544
+
545
+ RestClient.get('www.example.org', '/foo/bar') # ===> Allowed
546
+ RestClient.get('sample.org', '/foo') # ===> Allowed
547
+ RestClient.get('sample.org', '/bar') # ===> Failure
548
+ ```
549
+
550
+ With an object that responds to `#call`, receiving a `URI` object and returning a boolean:
551
+
552
+ ```ruby
553
+ blacklist = ['google.com', 'facebook.com', 'apple.com']
554
+ allowed_sites = lambda{|uri|
555
+ blacklist.none?{|site| uri.host.include?(site) }
556
+ }
557
+ WebMock.disable_net_connect!(allow: allowed_sites)
558
+
559
+ RestClient.get('www.example.org', '/') # ===> Allowed
560
+ RestClient.get('www.facebook.com', '/') # ===> Failure
561
+ RestClient.get('apple.com', '/') # ===> Failure
562
+ ```
563
+
564
+ With an `Array` of any of the above:
565
+
566
+ ```ruby
567
+ WebMock.disable_net_connect!(allow: [
568
+ lambda{|uri| uri.host.length % 2 == 0 },
569
+ /ample.org/,
570
+ 'bbc.co.uk',
571
+ ])
572
+
573
+ RestClient.get('www.example.org', '/') # ===> Allowed
574
+ RestClient.get('bbc.co.uk', '/') # ===> Allowed
575
+ RestClient.get('bbc.com', '/') # ===> Allowed
576
+ RestClient.get('www.bbc.com', '/') # ===> Failure
577
+ ```
353
578
 
354
579
  ## Connecting on Net::HTTP.start
355
580
 
@@ -364,133 +589,207 @@ so when there is no request, `Net::HTTP.start` doesn't do anything.
364
589
  **This means that WebMock breaks the Net::HTTP behaviour by default!**
365
590
 
366
591
  To workaround this issue, WebMock offers `:net_http_connect_on_start` option,
367
- which can be passed to `WebMock.allow_net_connect!` and `WebMock#disable_net_connect!` methods, i.e.
592
+ which can be passed to `WebMock.allow_net_connect!` and `WebMock.disable_net_connect!` methods, i.e.
368
593
 
369
- WebMock.allow_net_connect!(:net_http_connect_on_start => true)
594
+ ```ruby
595
+ WebMock.allow_net_connect!(net_http_connect_on_start: true)
596
+ ```
370
597
 
371
598
  This forces WebMock Net::HTTP adapter to always connect on `Net::HTTP.start`.
372
599
 
373
600
  ## Setting Expectations
374
601
 
375
602
  ### Setting expectations in Test::Unit
376
- require 'webmock/test_unit'
377
603
 
378
- stub_request(:any, "www.example.com")
604
+ ```ruby
605
+ require 'webmock/test_unit'
606
+
607
+ stub_request(:any, "www.example.com")
379
608
 
380
- uri = URI.parse('http://www.example.com/')
381
- req = Net::HTTP::Post.new(uri.path)
382
- req['Content-Length'] = 3
383
- res = Net::HTTP.start(uri.host, uri.port) {|http|
384
- http.request(req, 'abc')
385
- }
609
+ uri = URI.parse('http://www.example.com/')
610
+ req = Net::HTTP::Post.new(uri.path)
611
+ req['Content-Length'] = 3
386
612
 
387
- assert_requested :post, "http://www.example.com",
388
- :headers => {'Content-Length' => 3}, :body => "abc", :times => 1 # ===> Success
613
+ res = Net::HTTP.start(uri.host, uri.port) do |http|
614
+ http.request(req, 'abc')
615
+ end
389
616
 
390
- assert_not_requested :get, "http://www.something.com" # ===> Success
617
+ assert_requested :post, "http://www.example.com",
618
+ headers: {'Content-Length' => 3}, body: "abc",
619
+ times: 1 # ===> Success
391
620
 
392
- assert_requested(:post, "http://www.example.com", :times => 1) { |req| req.body == "abc" }
621
+ assert_not_requested :get, "http://www.something.com" # ===> Success
622
+
623
+ assert_requested(:post, "http://www.example.com",
624
+ times: 1) { |req| req.body == "abc" }
625
+ ```
393
626
 
394
627
  ### Expecting real (not stubbed) requests
395
628
 
396
- WebMock.allow_net_connect!
629
+ ```ruby
630
+ WebMock.allow_net_connect!
397
631
 
398
- Net::HTTP.get('www.example.com', '/') # ===> Success
632
+ Net::HTTP.get('www.example.com', '/') # ===> Success
399
633
 
400
- assert_requested :get, "http://www.example.com" # ===> Success
634
+ assert_requested :get, "http://www.example.com" # ===> Success
635
+ ```
401
636
 
402
637
  ### Setting expectations in Test::Unit on the stub
403
638
 
404
- stub_get = stub_request(:get, "www.example.com")
405
- stub_post = stub_request(:post, "www.example.com")
639
+ ```ruby
640
+ stub_get = stub_request(:get, "www.example.com")
641
+ stub_post = stub_request(:post, "www.example.com")
406
642
 
407
- Net::HTTP.get('www.example.com', '/')
643
+ Net::HTTP.get('www.example.com', '/')
408
644
 
409
- assert_requested(stub_get)
410
- assert_not_requested(stub_post)
645
+ assert_requested(stub_get)
646
+ assert_not_requested(stub_post)
647
+ ```
411
648
 
412
649
 
413
650
  ### Setting expectations in RSpec on `WebMock` module
414
- This style is borrowed from [fakeweb-matcher](http://github.com/freelancing-god/fakeweb-matcher)
651
+ This style is borrowed from [fakeweb-matcher](http://github.com/pat/fakeweb-matcher)
415
652
 
416
- require 'webmock/rspec'
653
+ ```ruby
654
+ require 'webmock/rspec'
417
655
 
418
- WebMock.should have_requested(:get, "www.example.com").with(:body => "abc", :headers => {'Content-Length' => 3}).twice
656
+ expect(WebMock).to have_requested(:get, "www.example.com").
657
+ with(body: "abc", headers: {'Content-Length' => 3}).twice
419
658
 
420
- WebMock.should_not have_requested(:get, "www.something.com")
659
+ expect(WebMock).not_to have_requested(:get, "www.something.com")
421
660
 
422
- WebMock.should have_requested(:post, "www.example.com").with { |req| req.body == "abc" }
661
+ expect(WebMock).to have_requested(:post, "www.example.com").
662
+ with { |req| req.body == "abc" }
663
+ # Note that the block with `do ... end` instead of curly brackets won't work!
664
+ # Why? See this comment https://github.com/bblimke/webmock/issues/174#issuecomment-34908908
423
665
 
424
- WebMock.should have_requested(:get, "www.example.com").with(:query => {"a" => ["b", "c"]})
666
+ expect(WebMock).to have_requested(:get, "www.example.com").
667
+ with(query: {"a" => ["b", "c"]})
425
668
 
426
- WebMock.should have_requested(:get, "www.example.com").with(:query => hash_including({"a" => ["b", "c"]}))
669
+ expect(WebMock).to have_requested(:get, "www.example.com").
670
+ with(query: hash_including({"a" => ["b", "c"]}))
427
671
 
428
- WebMock.should have_requested(:get, "www.example.com").
429
- with(:body => {"a" => ["b", "c"]}, :headers => {'Content-Type' => 'application/json'})
672
+ expect(WebMock).to have_requested(:get, "www.example.com").
673
+ with(body: {"a" => ["b", "c"]},
674
+ headers: {'Content-Type' => 'application/json'})
675
+ ```
430
676
 
431
677
  ### Setting expectations in RSpec with `a_request`
432
678
 
433
- a_request(:post, "www.example.com").with(:body => "abc", :headers => {'Content-Length' => 3}).should have_been_made.once
679
+ ```ruby
680
+ expect(a_request(:post, "www.example.com").
681
+ with(body: "abc", headers: {'Content-Length' => 3})).
682
+ to have_been_made.once
683
+
684
+ expect(a_request(:post, "www.something.com")).to have_been_made.times(3)
434
685
 
435
- a_request(:post, "www.something.com").should have_been_made.times(3)
686
+ expect(a_request(:post, "www.something.com")).to have_been_made.at_least_once
436
687
 
437
- a_request(:any, "www.example.com").should_not have_been_made
688
+ expect(a_request(:post, "www.something.com")).
689
+ to have_been_made.at_least_times(3)
438
690
 
439
- a_request(:post, "www.example.com").with { |req| req.body == "abc" }.should have_been_made
691
+ expect(a_request(:post, "www.something.com")).to have_been_made.at_most_twice
440
692
 
441
- a_request(:get, "www.example.com").with(:query => {"a" => ["b", "c"]}).should have_been_made
693
+ expect(a_request(:post, "www.something.com")).to have_been_made.at_most_times(3)
442
694
 
443
- a_request(:get, "www.example.com").with(:query => hash_including({"a" => ["b", "c"]})).should have_been_made
695
+ expect(a_request(:any, "www.example.com")).not_to have_been_made
444
696
 
445
- a_request(:post, "www.example.com").
446
- with(:body => {"a" => ["b", "c"]}, :headers => {'Content-Type' => 'application/json'}).should have_been_made
697
+ expect(a_request(:post, "www.example.com").with { |req| req.body == "abc" }).
698
+ to have_been_made
699
+
700
+ expect(a_request(:get, "www.example.com").with(query: {"a" => ["b", "c"]})).
701
+ to have_been_made
702
+
703
+ expect(a_request(:get, "www.example.com").
704
+ with(query: hash_including({"a" => ["b", "c"]}))).to have_been_made
705
+
706
+ expect(a_request(:post, "www.example.com").
707
+ with(body: {"a" => ["b", "c"]},
708
+ headers: {'Content-Type' => 'application/json'})).to have_been_made
709
+ ```
447
710
 
448
711
  ### Setting expectations in RSpec on the stub
449
712
 
450
- stub = stub_request(:get, "www.example.com")
451
- # ... make requests ...
452
- stub.should have_been_requested
713
+ ```ruby
714
+ stub = stub_request(:get, "www.example.com")
715
+ # ... make requests ...
716
+ expect(stub).to have_been_requested
717
+ ```
453
718
 
454
719
  ## Clearing stubs and request history
455
720
 
456
721
  If you want to reset all current stubs and history of requests use `WebMock.reset!`
457
722
 
458
- stub_request(:any, "www.example.com")
723
+ ```ruby
724
+ stub_request(:any, "www.example.com")
725
+
726
+ Net::HTTP.get('www.example.com', '/') # ===> Success
727
+
728
+ WebMock.reset!
729
+
730
+ Net::HTTP.get('www.example.com', '/') # ===> Failure
731
+
732
+ assert_not_requested :get, "www.example.com" # ===> Success
733
+ ```
734
+
735
+ ## Clearing request counters
736
+
737
+ If you want to reset **only** the counters of the executed requests use `WebMock.reset_executed_requests!`
738
+
739
+ ```ruby
740
+ stub = stub_request(:get, "www.example.com")
741
+ stub2 = stub_request(:get, "www.example2.com")
742
+
743
+ Net::HTTP.get('www.example.com', '/')
744
+ Net::HTTP.get('www.example.com', '/')
459
745
 
460
- Net::HTTP.get('www.example.com', '/') # ===> Success
746
+ Net::HTTP.get('www.example2.com', '/')
461
747
 
462
- WebMock.reset!
748
+ expect(stub).to have_been_requested.times(2)
749
+ expect(stub2).to have_been_requested.times(1)
463
750
 
464
- Net::HTTP.get('www.example.com', '/') # ===> Failure
751
+ WebMock.reset_executed_requests!
465
752
 
466
- assert_not_requested :get, "www.example.com" # ===> Success
753
+ expect(stub).not_to have_been_requested
754
+ expect(stub2).not_to have_been_requested
755
+ ```
467
756
 
468
757
  ## Disabling and enabling WebMock or only some http client adapters
469
758
 
470
- WebMock.disable! #disable WebMock (all adapters)
471
- WebMock.disable!(:except => [:net_http]) #disable WebMock for all libs except Net::HTTP
472
- WebMock.enable! #enable WebMock (all adapters)
473
- WebMock.enable!(:except => [:patron]) #enable WebMock for all libs except Patron
759
+ ```ruby
760
+ # Disable WebMock (all adapters)
761
+ WebMock.disable!
474
762
 
763
+ # Disable WebMock for all libs except Net::HTTP
764
+ WebMock.disable!(except: [:net_http])
765
+
766
+ # Enable WebMock (all adapters)
767
+ WebMock.enable!
768
+
769
+ # Enable WebMock for all libs except Patron
770
+ WebMock.enable!(except: [:patron])
771
+ ```
475
772
 
476
773
  ## Matching requests
477
774
 
478
775
  An executed request matches stubbed request if it passes following criteria:
479
776
 
480
- When request URI matches stubbed request URI string or Regexp pattern<br/>
481
- And request method is the same as stubbed request method or stubbed request method is :any<br/>
482
- And request body is the same as stubbed request body or stubbed request body is not specified<br/>
483
- And request headers match stubbed request headers, or stubbed request headers match a subset of request headers, or stubbed request headers are not specified<br/>
484
- And request matches provided block or block is not provided
777
+ - When request URI matches stubbed request URI string, Regexp pattern or RFC 6570 URI Template
778
+ - And request method is the same as stubbed request method or stubbed request method is :any
779
+ - And request body is the same as stubbed request body or stubbed request body is not specified
780
+ - And request headers match stubbed request headers, or stubbed request headers match a subset of request headers, or stubbed request headers are not specified
781
+ - And request matches provided block or block is not provided
485
782
 
486
783
  ## Precedence of stubs
487
784
 
488
785
  Always the last declared stub matching the request will be applied i.e:
489
786
 
490
- stub_request(:get, "www.example.com").to_return(:body => "abc")
491
- stub_request(:get, "www.example.com").to_return(:body => "def")
787
+ ```ruby
788
+ stub_request(:get, "www.example.com").to_return(body: "abc")
789
+ stub_request(:get, "www.example.com").to_return(body: "def")
492
790
 
493
- Net::HTTP.get('www.example.com', '/') # ====> "def"
791
+ Net::HTTP.get('www.example.com', '/') # ====> "def"
792
+ ```
494
793
 
495
794
  ## Matching URIs
496
795
 
@@ -498,93 +797,112 @@ WebMock will match all different representations of the same URI.
498
797
 
499
798
  I.e all the following representations of the URI are equal:
500
799
 
501
- "www.example.com"
502
- "www.example.com/"
503
- "www.example.com:80"
504
- "www.example.com:80/"
505
- "http://www.example.com"
506
- "http://www.example.com/"
507
- "http://www.example.com:80"
508
- "http://www.example.com:80/"
509
-
510
- The following URIs with basic authentication are also equal for WebMock
511
-
512
- "a b:pass@www.example.com"
513
- "a b:pass@www.example.com/"
514
- "a b:pass@www.example.com:80"
515
- "a b:pass@www.example.com:80/"
516
- "http://a b:pass@www.example.com"
517
- "http://a b:pass@www.example.com/"
518
- "http://a b:pass@www.example.com:80"
519
- "http://a b:pass@www.example.com:80/"
520
- "a%20b:pass@www.example.com"
521
- "a%20b:pass@www.example.com/"
522
- "a%20b:pass@www.example.com:80"
523
- "a%20b:pass@www.example.com:80/"
524
- "http://a%20b:pass@www.example.com"
525
- "http://a%20b:pass@www.example.com/"
526
- "http://a%20b:pass@www.example.com:80"
527
- "http://a%20b:pass@www.example.com:80/"
800
+ ```ruby
801
+ "www.example.com"
802
+ "www.example.com/"
803
+ "www.example.com:80"
804
+ "www.example.com:80/"
805
+ "http://www.example.com"
806
+ "http://www.example.com/"
807
+ "http://www.example.com:80"
808
+ "http://www.example.com:80/"
809
+ ```
810
+
811
+ The following URIs with userinfo are also equal for WebMock
812
+
813
+ ```ruby
814
+ "a b:pass@www.example.com"
815
+ "a b:pass@www.example.com/"
816
+ "a b:pass@www.example.com:80"
817
+ "a b:pass@www.example.com:80/"
818
+ "http://a b:pass@www.example.com"
819
+ "http://a b:pass@www.example.com/"
820
+ "http://a b:pass@www.example.com:80"
821
+ "http://a b:pass@www.example.com:80/"
822
+ "a%20b:pass@www.example.com"
823
+ "a%20b:pass@www.example.com/"
824
+ "a%20b:pass@www.example.com:80"
825
+ "a%20b:pass@www.example.com:80/"
826
+ "http://a%20b:pass@www.example.com"
827
+ "http://a%20b:pass@www.example.com/"
828
+ "http://a%20b:pass@www.example.com:80"
829
+ "http://a%20b:pass@www.example.com:80/"
830
+ ```
528
831
 
529
832
  or these
530
833
 
531
- "www.example.com/my path/?a=my param&b=c"
532
- "www.example.com/my%20path/?a=my%20param&b=c"
533
- "www.example.com:80/my path/?a=my param&b=c"
534
- "www.example.com:80/my%20path/?a=my%20param&b=c"
535
- "http://www.example.com/my path/?a=my param&b=c"
536
- "http://www.example.com/my%20path/?a=my%20param&b=c"
537
- "http://www.example.com:80/my path/?a=my param&b=c"
538
- "http://www.example.com:80/my%20path/?a=my%20param&b=c"
539
-
834
+ ```ruby
835
+ "www.example.com/my path/?a=my param&b=c"
836
+ "www.example.com/my%20path/?a=my%20param&b=c"
837
+ "www.example.com:80/my path/?a=my param&b=c"
838
+ "www.example.com:80/my%20path/?a=my%20param&b=c"
839
+ "http://www.example.com/my path/?a=my param&b=c"
840
+ "http://www.example.com/my%20path/?a=my%20param&b=c"
841
+ "http://www.example.com:80/my path/?a=my param&b=c"
842
+ "http://www.example.com:80/my%20path/?a=my%20param&b=c"
843
+ ```
540
844
 
541
845
  If you provide Regexp to match URI, WebMock will try to match it against every valid form of the same url.
542
846
 
543
- I.e `/.*my param.*/` will match `www.example.com/my%20path` because it is equivalent of `www.example.com/my path`
847
+ I.e `/my path/` will match `www.example.com/my%20path` because it is equivalent of `www.example.com/my path`
544
848
 
849
+ ## Matching with URI Templates
850
+
851
+ If you use [Addressable::Template](https://github.com/sporkmonger/addressable#uri-templates) for matching, then WebMock will defer the matching rules to Addressable, which complies with [RFC 6570](http://tools.ietf.org/html/rfc6570).
852
+
853
+ If you use any of the WebMock methods for matching query params, then Addressable will be used to match the base URI and WebMock will match the query params. If you do not, then WebMock will let Addressable match the full URI.
545
854
 
546
855
  ## Matching headers
547
856
 
548
857
  WebMock will match request headers against stubbed request headers in the following situations:
549
858
 
550
859
  1. Stubbed request has headers specified and request headers are the same as stubbed headers <br/>
551
- i.e stubbed headers: `{ 'Header1' => 'Value1', 'Header1' => 'Value1' }`, requested: `{ 'Header1' => 'Value1', 'Header1' => 'Value1' }`
860
+ i.e stubbed headers: `{ 'Header1' => 'Value1', 'Header2' => 'Value2' }`, requested: `{ 'Header1' => 'Value1', 'Header2' => 'Value2' }`
552
861
 
553
862
  2. Stubbed request has headers specified and stubbed request headers are a subset of request headers <br/>
554
- i.e stubbed headers: `{ 'Header1' => 'Value1' }`, requested: `{ 'Header1' => 'Value1', 'Header1' => 'Value1' }`
863
+ i.e stubbed headers: `{ 'Header1' => 'Value1' }`, requested: `{ 'Header1' => 'Value1', 'Header2' => 'Value2' }`
555
864
 
556
865
  3. Stubbed request has no headers <br/>
557
- i.e stubbed headers: `nil`, requested: `{ 'Header1' => 'Value1', 'Header1' => 'Value1' }`
866
+ i.e stubbed headers: `nil`, requested: `{ 'Header1' => 'Value1', 'Header2' => 'Value2' }`
558
867
 
559
868
  WebMock normalises headers and treats all forms of same headers as equal:
560
869
  i.e the following two sets of headers are equal:
561
870
 
562
- `{ "Header1" => "value1", :content_length => 123, :X_CuStOm_hEAder => :value }`
871
+ `{ "Header1" => "value1", content_length: 123, X_CuStOm_hEAder: :value }`
563
872
 
564
- `{ :header1 => "value1", "Content-Length" => 123, "x-cuSTOM-HeAder" => "value" }`
873
+ `{ header1: "value1", "Content-Length" => 123, "x-cuSTOM-HeAder" => "value" }`
565
874
 
566
875
  ## Recording real requests and responses and replaying them later
567
876
 
568
- To record your application's real HTTP interactions and replay them later in tests you can use [VCR](http://github.com/myronmarston/vcr) with WebMock.
877
+ To record your application's real HTTP interactions and replay them later in tests you can use [VCR](https://github.com/vcr/vcr) with WebMock.
569
878
 
570
879
  ## Request callbacks
571
880
 
572
- ####WebMock can invoke callbacks stubbed or real requests:
881
+ #### WebMock can invoke callbacks stubbed or real requests:
573
882
 
574
- WebMock.after_request do |request_signature, response|
575
- puts "Request #{request_signature} was made and #{response} was returned"
576
- end
883
+ ```ruby
884
+ WebMock.after_request do |request_signature, response|
885
+ puts "Request #{request_signature} was made and #{response} was returned"
886
+ end
887
+ ```
577
888
 
578
889
  #### invoke callbacks for real requests only and except requests made with Patron
579
890
 
580
- WebMock.after_request(:except => [:patron], :real_requests_only => true) do |request_signature, response|
581
- puts "Request #{request_signature} was made and #{response} was returned"
582
- end
891
+ ```ruby
892
+ WebMock.after_request(except: [:patron],
893
+ real_requests_only: true) do |req_signature, response|
894
+ puts "Request #{req_signature} was made and #{response} was returned"
895
+ end
896
+ ```
583
897
 
584
898
  ## Bugs and Issues
585
899
 
586
900
  Please submit them here [http://github.com/bblimke/webmock/issues](http://github.com/bblimke/webmock/issues)
587
901
 
902
+ ## Issue triage [![Open Source Helpers](https://www.codetriage.com/bblimke/webmock/badges/users.svg)](https://www.codetriage.com/bblimke/webmock)
903
+
904
+ You can contribute by triaging issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to webmock on CodeTriage](https://www.codetriage.com/bblimke/webmock).
905
+
588
906
  ## Suggestions
589
907
 
590
908
  If you have any suggestions on how to improve WebMock please send an email to the mailing list [groups.google.com/group/webmock-users](http://groups.google.com/group/webmock-users)
@@ -597,45 +915,6 @@ In order to work on Webmock you first need to fork and clone the repo.
597
915
  Please do any work on a dedicated branch and rebase against master
598
916
  before sending a pull request.
599
917
 
600
- #### Running Tests
601
-
602
- We use RVM in order to test WebMock against 1.8.6, REE, 1.8.7, 1.9.2 and
603
- jRuby. You can get RVM setup for WebMock development using the
604
- following commands (if you don't have these version of Ruby installed
605
- use `rvm install` to install each of them).
606
-
607
- rvm use --create 1.8.6@webmock
608
- gem install jeweler bundler
609
- bundle install
610
-
611
- rvm use --create ree@webmock
612
- gem install jeweler bundler
613
- bundle install
614
-
615
- rvm use --create 1.8.7@webmock
616
- gem install jeweler bundler
617
- bundle install
618
-
619
- rvm use --create 1.9.2@webmock
620
- gem install jeweler bundler
621
- bundle install
622
-
623
- rvm use --create jruby@webmock
624
- gem install jeweler bundler
625
- bundle install
626
-
627
- These commands will create a gemset named WebMock for each of the
628
- supported versions of Ruby and `bundle install` all dependencies.
629
-
630
- With the supported versions of Ruby installed RVM will run specs across
631
- all version with just one command.
632
-
633
- bundle exec rvm 1.8.6@webmock,ree@webmock,1.8.7@webmock,1.9.2@webmock,jruby@webmock rspec spec/**/*_spec.rb
634
-
635
- This command is wrapped up in to a rake task and can be invoked like so:
636
-
637
- rake spec:rubies
638
-
639
918
  ## Credits
640
919
 
641
920
  The initial lines of this project were written during New Bamboo [Hack Day](http://blog.new-bamboo.co.uk/2009/11/13/hackday-results)
@@ -705,6 +984,183 @@ People who submitted patches and new features or suggested improvements. Many th
705
984
  * jugyo
706
985
  * aindustries
707
986
  * Eric Oestrich
987
+ * erwanlr
988
+ * Ben Bleything
989
+ * Jon Leighton
990
+ * Ryan Schlesinger
991
+ * Julien Boyer
992
+ * Kevin Glowacz
993
+ * Hans Hasselberg
994
+ * Andrew France
995
+ * Jonathan Hyman
996
+ * Rex Feng
997
+ * Pavel Forkert
998
+ * Jordi Massaguer Pla
999
+ * Jake Benilov
1000
+ * Tom Beauvais
1001
+ * Mokevnin Kirill
1002
+ * Alex Grant
1003
+ * Lucas Dohmen
1004
+ * Bastien Vaucher
1005
+ * Joost Baaij
1006
+ * Joel Chippindale
1007
+ * Murahashi Sanemat Kenichi
1008
+ * Tim Kurvers
1009
+ * Ilya Vassilevsky
1010
+ * gotwalt
1011
+ * Leif Bladt
1012
+ * Alex Tomlins
1013
+ * Mitsutaka Mimura
1014
+ * Tomy Kaira
1015
+ * Daniel van Hoesel
1016
+ * Ian Asaff
1017
+ * Ian Lesperance
1018
+ * Matthew Horan
1019
+ * Dmitry Gutov
1020
+ * Florian Dütsch
1021
+ * Manuel Meurer
1022
+ * Brian D. Burns
1023
+ * Riley Strong
1024
+ * Tamir Duberstein
1025
+ * Stefano Uliari
1026
+ * Alex Stupakov
1027
+ * Karen Wang
1028
+ * Matt Burke
1029
+ * Jon Rowe
1030
+ * Aleksey V. Zapparov
1031
+ * Praveen Arimbrathodiyil
1032
+ * Bo Jeanes
1033
+ * Matthew Conway
1034
+ * Rob Olson
1035
+ * Max Lincoln
1036
+ * Oleg Gritsenko
1037
+ * Hwan-Joon Choi
1038
+ * SHIBATA Hiroshi
1039
+ * Caleb Thompson
1040
+ * Theo Hultberg
1041
+ * Pablo Jairala
1042
+ * Insoo Buzz Jung
1043
+ * Carlos Alonso Pérez
1044
+ * trlorenz
1045
+ * Alexander Simonov
1046
+ * Thorbjørn Hermanse
1047
+ * Mark Lorenz
1048
+ * tjsousa
1049
+ * Tasos Stathopoulos
1050
+ * Dan Buettner
1051
+ * Sven Riedel
1052
+ * Mark Lorenz
1053
+ * Dávid Kovács
1054
+ * fishermand46
1055
+ * Franky Wahl
1056
+ * ChaYoung You
1057
+ * Simon Russell
1058
+ * Steve Mitchell
1059
+ * Mattias Putman
1060
+ * Zachary Anker
1061
+ * Emmanuel Sambo
1062
+ * Ramon Tayag
1063
+ * Johannes Schlumberger
1064
+ * Siôn Le Roux
1065
+ * Matt Palmer
1066
+ * Zhao Wen
1067
+ * Krzysztof Rygielski
1068
+ * Magne Land
1069
+ * yurivm
1070
+ * Mike Knepper
1071
+ * Charles Pence
1072
+ * Alexey Zapparov
1073
+ * Pablo Brasero
1074
+ * Cedric Pimenta
1075
+ * Michiel Karnebeek
1076
+ * Alex Kestner
1077
+ * Manfred Stienstra
1078
+ * Tim Diggins
1079
+ * Gabriel Chaney
1080
+ * Chris Griego
1081
+ * Taiki Ono
1082
+ * Jonathan Schatz
1083
+ * Jose Luis Honorato
1084
+ * Aaron Kromer
1085
+ * Pavel Jurašek
1086
+ * Jake Worth
1087
+ * Gabe Martin-Dempesy
1088
+ * Michael Grosser
1089
+ * Aleksei Maridashvili
1090
+ * Ville Lautanala
1091
+ * Koichi ITO
1092
+ * Jordan Harband
1093
+ * Tarmo Tänav
1094
+ * Joe Marty
1095
+ * Chris Thomson
1096
+ * Vít Ondruch
1097
+ * George Ulmer
1098
+ * Christof Koenig
1099
+ * Chung-Yi Chi
1100
+ * Olexandr Hoshylyk
1101
+ * Janko Marohnić
1102
+ * Pat Allan
1103
+ * Rick Song
1104
+ * NARUSE, Yui
1105
+ * Piotr Boniecki
1106
+ * Olia Kremmyda
1107
+ * Michał Matyas
1108
+ * Matt Brictson
1109
+ * Kenny Ortmann
1110
+ * redbar0n
1111
+ * Lukas Pokorny
1112
+ * Arkadiy Tetelman
1113
+ * Kazato Sugimoto
1114
+ * Olle Jonsson
1115
+ * Pavel Rosický
1116
+ * Geremia Taglialatela
1117
+ * Koichi Sasada
1118
+ * Yusuke Endoh
1119
+ * Grey Baker
1120
+ * SoonKhen OwYong
1121
+ * Pavel Valena
1122
+ * Adam Sokolnicki
1123
+ * Jeff Felchner
1124
+ * Eike Send
1125
+ * Claudio Poli
1126
+ * Csaba Apagyi
1127
+ * Frederick Cheung
1128
+ * Fábio D. Batista
1129
+ * Andriy Yanko
1130
+ * y-yagi
1131
+ * Rafael França
1132
+ * George Claghorn
1133
+ * Alex Junger
1134
+ * Orien Madgwick
1135
+ * Andrei Sidorov
1136
+ * Marco Costa
1137
+ * Ryan Davis
1138
+ * Brandur
1139
+ * Samuel Williams
1140
+ * Patrik Ragnarsson
1141
+ * Alex Coomans
1142
+ * Vesa Laakso
1143
+ * John Hawthorn
1144
+ * guppy0356
1145
+ * Thilo Rusche
1146
+ * Andrew Stuntz
1147
+ * Lucas Uyezu
1148
+ * Bruno Sutic
1149
+ * Ryan Kerr
1150
+ * Adam Harwood
1151
+ * Ben Koshy
1152
+ * Jesse Bowes
1153
+ * Marek Kasztelnik
1154
+ * ce07c3
1155
+ * Jun Jiang
1156
+ * Oleksiy Kovyrin
1157
+ * Matt Larraz
1158
+ * Tony Schneider
1159
+ * Niklas Hösl
1160
+ * Johanna Hartmann
1161
+ * Alex Vondrak
1162
+ * Will Storey
1163
+ * Eduardo Hernandez
708
1164
 
709
1165
  For a full list of contributors you can visit the
710
1166
  [contributors](https://github.com/bblimke/webmock/contributors) page.