webmock 1.8.6 → 3.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/CI.yml +37 -0
- data/.gitignore +6 -0
- data/CHANGELOG.md +1198 -0
- data/Gemfile +3 -15
- data/README.md +761 -305
- data/Rakefile +13 -40
- data/lib/webmock/api.rb +63 -17
- data/lib/webmock/callback_registry.rb +1 -1
- data/lib/webmock/config.rb +8 -0
- data/lib/webmock/cucumber.rb +2 -0
- data/lib/webmock/errors.rb +8 -24
- data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +216 -0
- data/lib/webmock/http_lib_adapters/curb_adapter.rb +148 -84
- data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +224 -4
- data/lib/webmock/http_lib_adapters/excon_adapter.rb +104 -34
- data/lib/webmock/http_lib_adapters/http_rb/client.rb +17 -0
- data/lib/webmock/http_lib_adapters/http_rb/request.rb +16 -0
- data/lib/webmock/http_lib_adapters/http_rb/response.rb +64 -0
- data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +29 -0
- data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +68 -0
- data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +37 -0
- data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +152 -86
- data/lib/webmock/http_lib_adapters/manticore_adapter.rb +145 -0
- data/lib/webmock/http_lib_adapters/net_http.rb +155 -46
- data/lib/webmock/http_lib_adapters/net_http_response.rb +1 -1
- data/lib/webmock/http_lib_adapters/patron_adapter.rb +16 -15
- data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +76 -82
- data/lib/webmock/matchers/any_arg_matcher.rb +13 -0
- data/lib/webmock/matchers/hash_argument_matcher.rb +21 -0
- data/lib/webmock/matchers/hash_excluding_matcher.rb +15 -0
- data/lib/webmock/matchers/hash_including_matcher.rb +4 -12
- data/lib/webmock/minitest.rb +29 -3
- data/lib/webmock/rack_response.rb +14 -7
- data/lib/webmock/request_body_diff.rb +64 -0
- data/lib/webmock/request_execution_verifier.rb +38 -17
- data/lib/webmock/request_pattern.rb +158 -38
- data/lib/webmock/request_registry.rb +3 -3
- data/lib/webmock/request_signature.rb +7 -3
- data/lib/webmock/request_signature_snippet.rb +61 -0
- data/lib/webmock/request_stub.rb +9 -6
- data/lib/webmock/response.rb +30 -15
- data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +38 -2
- data/lib/webmock/rspec/matchers/webmock_matcher.rb +23 -2
- data/lib/webmock/rspec/matchers.rb +0 -1
- data/lib/webmock/rspec.rb +11 -2
- data/lib/webmock/stub_registry.rb +31 -10
- data/lib/webmock/stub_request_snippet.rb +14 -6
- data/lib/webmock/test_unit.rb +4 -4
- data/lib/webmock/util/hash_counter.rb +20 -6
- data/lib/webmock/util/hash_keys_stringifier.rb +5 -3
- data/lib/webmock/util/hash_validator.rb +17 -0
- data/lib/webmock/util/headers.rb +23 -2
- data/lib/webmock/util/json.rb +20 -7
- data/lib/webmock/util/query_mapper.rb +281 -0
- data/lib/webmock/util/uri.rb +29 -19
- data/lib/webmock/util/values_stringifier.rb +20 -0
- data/lib/webmock/util/version_checker.rb +40 -2
- data/lib/webmock/version.rb +1 -1
- data/lib/webmock/webmock.rb +56 -17
- data/lib/webmock.rb +56 -46
- data/minitest/test_helper.rb +8 -3
- data/minitest/test_webmock.rb +4 -1
- data/minitest/webmock_spec.rb +16 -6
- data/spec/acceptance/async_http_client/async_http_client_spec.rb +375 -0
- data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +73 -0
- data/spec/acceptance/curb/curb_spec.rb +227 -68
- data/spec/acceptance/curb/curb_spec_helper.rb +11 -8
- data/spec/acceptance/em_http_request/em_http_request_spec.rb +322 -28
- data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +15 -10
- data/spec/acceptance/excon/excon_spec.rb +66 -4
- data/spec/acceptance/excon/excon_spec_helper.rb +21 -7
- data/spec/acceptance/http_rb/http_rb_spec.rb +93 -0
- data/spec/acceptance/http_rb/http_rb_spec_helper.rb +54 -0
- data/spec/acceptance/httpclient/httpclient_spec.rb +152 -11
- data/spec/acceptance/httpclient/httpclient_spec_helper.rb +25 -16
- data/spec/acceptance/manticore/manticore_spec.rb +107 -0
- data/spec/acceptance/manticore/manticore_spec_helper.rb +35 -0
- data/spec/acceptance/net_http/net_http_shared.rb +52 -24
- data/spec/acceptance/net_http/net_http_spec.rb +164 -50
- data/spec/acceptance/net_http/net_http_spec_helper.rb +19 -10
- data/spec/acceptance/net_http/real_net_http_spec.rb +1 -1
- data/spec/acceptance/patron/patron_spec.rb +29 -40
- data/spec/acceptance/patron/patron_spec_helper.rb +15 -11
- data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +229 -58
- data/spec/acceptance/shared/callbacks.rb +32 -30
- data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +20 -5
- data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +14 -14
- data/spec/acceptance/shared/precedence_of_stubs.rb +6 -6
- data/spec/acceptance/shared/request_expectations.rb +560 -296
- data/spec/acceptance/shared/returning_declared_responses.rb +180 -138
- data/spec/acceptance/shared/stubbing_requests.rb +385 -154
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +78 -17
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +19 -15
- data/spec/acceptance/webmock_shared.rb +2 -2
- data/spec/fixtures/test.txt +1 -0
- data/spec/quality_spec.rb +27 -3
- data/spec/spec_helper.rb +11 -20
- data/spec/support/failures.rb +9 -0
- data/spec/support/my_rack_app.rb +8 -3
- data/spec/support/network_connection.rb +7 -13
- data/spec/support/webmock_server.rb +8 -3
- data/spec/unit/api_spec.rb +175 -0
- data/spec/unit/errors_spec.rb +116 -19
- data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +1 -1
- data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +2 -2
- data/spec/unit/matchers/hash_excluding_matcher_spec.rb +61 -0
- data/spec/unit/matchers/hash_including_matcher_spec.rb +87 -0
- data/spec/unit/rack_response_spec.rb +54 -16
- data/spec/unit/request_body_diff_spec.rb +90 -0
- data/spec/unit/request_execution_verifier_spec.rb +147 -39
- data/spec/unit/request_pattern_spec.rb +462 -198
- data/spec/unit/request_registry_spec.rb +29 -9
- data/spec/unit/request_signature_snippet_spec.rb +89 -0
- data/spec/unit/request_signature_spec.rb +91 -49
- data/spec/unit/request_stub_spec.rb +71 -70
- data/spec/unit/response_spec.rb +100 -81
- data/spec/unit/stub_registry_spec.rb +37 -20
- data/spec/unit/stub_request_snippet_spec.rb +51 -31
- data/spec/unit/util/hash_counter_spec.rb +6 -6
- data/spec/unit/util/hash_keys_stringifier_spec.rb +4 -4
- data/spec/unit/util/headers_spec.rb +4 -4
- data/spec/unit/util/json_spec.rb +29 -3
- data/spec/unit/util/query_mapper_spec.rb +157 -0
- data/spec/unit/util/uri_spec.rb +150 -36
- data/spec/unit/util/version_checker_spec.rb +15 -9
- data/spec/unit/webmock_spec.rb +57 -4
- data/test/http_request.rb +3 -3
- data/test/shared_test.rb +45 -13
- data/test/test_helper.rb +1 -1
- data/test/test_webmock.rb +6 -0
- data/webmock.gemspec +30 -11
- metadata +308 -199
- data/.rvmrc +0 -1
- data/.travis.yml +0 -11
- data/Guardfile +0 -24
- data/lib/webmock/http_lib_adapters/em_http_request/em_http_request_0_x.rb +0 -151
- 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
|
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
|
21
|
+
* Support for RSpec
|
16
22
|
* Support for MiniTest
|
17
23
|
|
18
24
|
Supported HTTP libraries
|
19
25
|
------------------------
|
20
26
|
|
21
|
-
*
|
22
|
-
*
|
23
|
-
*
|
24
|
-
*
|
25
|
-
*
|
26
|
-
*
|
27
|
-
*
|
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
|
33
|
-
* MRI
|
34
|
-
* MRI
|
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
|
-
|
52
|
-
|
53
|
-
Add the following code to `test/test_helper.rb`
|
70
|
+
## Upgrading from v1.x to v2.x
|
54
71
|
|
55
|
-
|
72
|
+
WebMock 2.x has changed somewhat since version 1.x. Changes are listed in [CHANGELOG.md](CHANGELOG.md)
|
56
73
|
|
57
|
-
###
|
74
|
+
### Cucumber
|
58
75
|
|
59
|
-
|
76
|
+
Create a file `features/support/webmock.rb` with the following contents:
|
60
77
|
|
61
|
-
|
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
|
-
|
86
|
+
```ruby
|
87
|
+
require 'webmock/minitest'
|
88
|
+
```
|
68
89
|
|
69
|
-
###
|
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 `
|
100
|
+
Add the following code to `test/test_helper.rb`
|
72
101
|
|
73
|
-
|
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
|
-
|
80
|
-
|
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
|
-
|
123
|
+
```ruby
|
124
|
+
stub_request(:any, "www.example.com")
|
92
125
|
|
93
|
-
|
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
|
-
|
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
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
109
|
-
|
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
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
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
|
-
|
121
|
-
|
162
|
+
```ruby
|
163
|
+
stub_request(:post, "www.example.com").
|
164
|
+
with(body: {data: {a: '1', b: 'five'}})
|
122
165
|
|
123
|
-
|
124
|
-
|
166
|
+
RestClient.post('www.example.com', "data[a]=1&data[b]=five",
|
167
|
+
content_type: 'application/x-www-form-urlencoded') # ===> Success
|
125
168
|
|
126
|
-
|
127
|
-
|
169
|
+
RestClient.post('www.example.com', '{"data":{"a":"1","b":"five"}}',
|
170
|
+
content_type: 'application/json') # ===> Success
|
128
171
|
|
129
|
-
|
130
|
-
|
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
|
-
|
135
|
-
|
178
|
+
```ruby
|
179
|
+
stub_request(:post, "www.example.com").
|
180
|
+
with(body: hash_including({data: {a: '1', b: 'five'}}))
|
136
181
|
|
137
|
-
|
138
|
-
|
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
|
-
|
188
|
+
```ruby
|
189
|
+
stub_request(:any, "www.example.com").
|
190
|
+
with(headers:{ 'Header-Name' => 'Header-Value' })
|
143
191
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|
-
|
203
|
+
```ruby
|
204
|
+
stub_request(:get, 'www.example.com').
|
205
|
+
with(headers: {'Accept' => ['image/jpeg', 'image/png'] })
|
154
206
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
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
|
-
|
163
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
281
|
+
```ruby
|
282
|
+
stub_request(:get, "www.example.com").with(query: {"a" => ["b", "c"]})
|
184
283
|
|
185
|
-
|
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
|
-
|
289
|
+
```ruby
|
290
|
+
stub_request(:get, "www.example.com").
|
291
|
+
with(query: hash_including({"a" => ["b", "c"]}))
|
190
292
|
|
191
|
-
|
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
|
-
|
308
|
+
```ruby
|
309
|
+
stub_request(:any, "www.example.com").
|
310
|
+
to_return(body: "abc", status: 200,
|
311
|
+
headers: { 'Content-Length' => 3 })
|
196
312
|
|
197
|
-
|
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
|
-
|
324
|
+
```ruby
|
325
|
+
File.open('/tmp/response_body.txt', 'w') { |f| f.puts 'abc' }
|
202
326
|
|
203
|
-
|
327
|
+
stub_request(:any, "www.example.com").
|
328
|
+
to_return(body: File.new('/tmp/response_body.txt'), status: 200)
|
204
329
|
|
205
|
-
|
330
|
+
Net::HTTP.get('www.example.com', '/') # ===> "abc\n"
|
331
|
+
```
|
206
332
|
|
207
333
|
### Response with custom status message
|
208
334
|
|
209
|
-
|
335
|
+
```ruby
|
336
|
+
stub_request(:any, "www.example.com").
|
337
|
+
to_return(status: [500, "Internal Server Error"])
|
210
338
|
|
211
|
-
|
212
|
-
|
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
|
-
|
217
|
-
|
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
|
-
|
356
|
+
```ruby
|
357
|
+
stub_request(:get, "www.example.com").to_return(raw_response_file)
|
358
|
+
```
|
222
359
|
|
223
360
|
or string
|
224
361
|
|
225
|
-
|
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
|
-
|
230
|
-
|
368
|
+
```ruby
|
369
|
+
stub_request(:any, 'www.example.net').
|
370
|
+
to_return { |request| {body: request.body} }
|
231
371
|
|
232
|
-
|
372
|
+
RestClient.post('www.example.net', 'abc') # ===> "abc\n"
|
373
|
+
```
|
233
374
|
|
234
375
|
### Responses dynamically evaluated from lambda
|
235
376
|
|
236
|
-
|
237
|
-
|
377
|
+
```ruby
|
378
|
+
stub_request(:any, 'www.example.net').
|
379
|
+
to_return(lambda { |request| {body: request.body} })
|
238
380
|
|
239
|
-
|
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
|
-
|
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
|
-
|
249
|
-
|
394
|
+
```ruby
|
395
|
+
stub_request(:any, 'www.example.net').
|
396
|
+
to_return(body: lambda { |request| request.body })
|
250
397
|
|
251
|
-
|
398
|
+
RestClient.post('www.example.net', 'abc') # ===> "abc\n"
|
399
|
+
```
|
252
400
|
|
253
401
|
### Rack responses
|
254
402
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
403
|
+
```ruby
|
404
|
+
class MyRackApp
|
405
|
+
def self.call(env)
|
406
|
+
[200, {}, ["Hello"]]
|
407
|
+
end
|
408
|
+
end
|
260
409
|
|
261
|
-
|
410
|
+
stub_request(:get, "www.example.com").to_rack(MyRackApp)
|
262
411
|
|
263
|
-
|
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
|
-
|
419
|
+
```ruby
|
420
|
+
stub_request(:any, 'www.example.net').to_raise(StandardError)
|
270
421
|
|
271
|
-
|
422
|
+
RestClient.post('www.example.net', 'abc') # ===> StandardError
|
423
|
+
```
|
272
424
|
|
273
425
|
#### or by exception instance
|
274
426
|
|
275
|
-
|
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
|
-
|
433
|
+
```ruby
|
434
|
+
stub_request(:any, 'www.example.net').to_raise("some error")
|
435
|
+
```
|
280
436
|
|
281
437
|
### Raising timeout errors
|
282
438
|
|
283
|
-
|
439
|
+
```ruby
|
440
|
+
stub_request(:any, 'www.example.net').to_timeout
|
284
441
|
|
285
|
-
|
442
|
+
RestClient.post('www.example.net', 'abc') # ===> RestClient::RequestTimeout
|
443
|
+
```
|
286
444
|
|
287
445
|
### Multiple responses for repeated requests
|
288
446
|
|
289
|
-
|
290
|
-
|
291
|
-
|
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
|
-
|
453
|
+
#after all responses are used the last response will be returned infinitely
|
294
454
|
|
295
|
-
|
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
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
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
|
-
|
310
|
-
|
311
|
-
|
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
|
-
|
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
|
-
|
492
|
+
```ruby
|
493
|
+
WebMock.allow_net_connect!
|
321
494
|
|
322
|
-
|
495
|
+
stub_request(:any, "www.example.com").to_return(body: "abc")
|
323
496
|
|
324
|
-
|
497
|
+
Net::HTTP.get('www.example.com', '/') # ===> "abc"
|
325
498
|
|
326
|
-
|
499
|
+
Net::HTTP.get('www.something.com', '/') # ===> /.+Something.+/
|
327
500
|
|
328
|
-
|
501
|
+
WebMock.disable_net_connect!
|
329
502
|
|
330
|
-
|
503
|
+
Net::HTTP.get('www.something.com', '/') # ===> Failure
|
504
|
+
```
|
331
505
|
|
332
506
|
### External requests can be disabled while allowing localhost
|
333
507
|
|
334
|
-
|
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
|
-
|
516
|
+
### External requests can be disabled while allowing specific requests
|
337
517
|
|
338
|
-
|
518
|
+
Allowed requests can be specified in a number of ways.
|
339
519
|
|
340
|
-
|
520
|
+
With a `String` specifying a host name:
|
341
521
|
|
342
|
-
|
522
|
+
```ruby
|
523
|
+
WebMock.disable_net_connect!(allow: 'www.example.org')
|
343
524
|
|
344
|
-
|
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
|
-
|
530
|
+
With a `String` specifying a host name and a port:
|
347
531
|
|
348
|
-
|
532
|
+
```ruby
|
533
|
+
WebMock.disable_net_connect!(allow: 'www.example.org:8080')
|
349
534
|
|
350
|
-
|
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
|
-
|
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
|
592
|
+
which can be passed to `WebMock.allow_net_connect!` and `WebMock.disable_net_connect!` methods, i.e.
|
368
593
|
|
369
|
-
|
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
|
-
|
604
|
+
```ruby
|
605
|
+
require 'webmock/test_unit'
|
606
|
+
|
607
|
+
stub_request(:any, "www.example.com")
|
379
608
|
|
380
|
-
|
381
|
-
|
382
|
-
|
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
|
-
|
388
|
-
|
613
|
+
res = Net::HTTP.start(uri.host, uri.port) do |http|
|
614
|
+
http.request(req, 'abc')
|
615
|
+
end
|
389
616
|
|
390
|
-
|
617
|
+
assert_requested :post, "http://www.example.com",
|
618
|
+
headers: {'Content-Length' => 3}, body: "abc",
|
619
|
+
times: 1 # ===> Success
|
391
620
|
|
392
|
-
|
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
|
-
|
629
|
+
```ruby
|
630
|
+
WebMock.allow_net_connect!
|
397
631
|
|
398
|
-
|
632
|
+
Net::HTTP.get('www.example.com', '/') # ===> Success
|
399
633
|
|
400
|
-
|
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
|
-
|
405
|
-
|
639
|
+
```ruby
|
640
|
+
stub_get = stub_request(:get, "www.example.com")
|
641
|
+
stub_post = stub_request(:post, "www.example.com")
|
406
642
|
|
407
|
-
|
643
|
+
Net::HTTP.get('www.example.com', '/')
|
408
644
|
|
409
|
-
|
410
|
-
|
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/
|
651
|
+
This style is borrowed from [fakeweb-matcher](http://github.com/pat/fakeweb-matcher)
|
415
652
|
|
416
|
-
|
653
|
+
```ruby
|
654
|
+
require 'webmock/rspec'
|
417
655
|
|
418
|
-
|
656
|
+
expect(WebMock).to have_requested(:get, "www.example.com").
|
657
|
+
with(body: "abc", headers: {'Content-Length' => 3}).twice
|
419
658
|
|
420
|
-
|
659
|
+
expect(WebMock).not_to have_requested(:get, "www.something.com")
|
421
660
|
|
422
|
-
|
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
|
-
|
666
|
+
expect(WebMock).to have_requested(:get, "www.example.com").
|
667
|
+
with(query: {"a" => ["b", "c"]})
|
425
668
|
|
426
|
-
|
669
|
+
expect(WebMock).to have_requested(:get, "www.example.com").
|
670
|
+
with(query: hash_including({"a" => ["b", "c"]}))
|
427
671
|
|
428
|
-
|
429
|
-
|
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
|
-
|
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
|
-
|
686
|
+
expect(a_request(:post, "www.something.com")).to have_been_made.at_least_once
|
436
687
|
|
437
|
-
|
688
|
+
expect(a_request(:post, "www.something.com")).
|
689
|
+
to have_been_made.at_least_times(3)
|
438
690
|
|
439
|
-
|
691
|
+
expect(a_request(:post, "www.something.com")).to have_been_made.at_most_twice
|
440
692
|
|
441
|
-
|
693
|
+
expect(a_request(:post, "www.something.com")).to have_been_made.at_most_times(3)
|
442
694
|
|
443
|
-
|
695
|
+
expect(a_request(:any, "www.example.com")).not_to have_been_made
|
444
696
|
|
445
|
-
|
446
|
-
|
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
|
-
|
451
|
-
|
452
|
-
|
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
|
-
|
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
|
-
|
746
|
+
Net::HTTP.get('www.example2.com', '/')
|
461
747
|
|
462
|
-
|
748
|
+
expect(stub).to have_been_requested.times(2)
|
749
|
+
expect(stub2).to have_been_requested.times(1)
|
463
750
|
|
464
|
-
|
751
|
+
WebMock.reset_executed_requests!
|
465
752
|
|
466
|
-
|
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
|
-
|
471
|
-
|
472
|
-
|
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
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
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
|
-
|
491
|
-
|
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
|
-
|
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
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
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
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
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
|
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', '
|
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', '
|
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', '
|
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", :
|
871
|
+
`{ "Header1" => "value1", content_length: 123, X_CuStOm_hEAder: :value }`
|
563
872
|
|
564
|
-
`{ :
|
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](
|
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
|
-
|
575
|
-
|
576
|
-
|
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
|
-
|
581
|
-
|
582
|
-
|
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.
|