Reputation: 838
In my cucumber support directory I have the following in vcr.rb:
require 'vcr'
VCR.configure do |c|
c.cassette_library_dir = 'fixtures/vcr_cassettes'
c.hook_into :webmock
c.ignore_localhost = true
c.default_cassette_options = { record: :new_episodes }
end
I am geocoding city names which makes calls to the Google Maps API. I'm trying to record and stub these requests, but it keeps recording the same requests to the same yml file:
- request:
method: get
uri: http://maps.googleapis.com/maps/api/geocode/json?address=Miami,%20FL&language=en&sensor=false
body:
encoding: US-ASCII
string: ''
headers:
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept:
- ! '*/*'
User-Agent:
- Ruby
# response...
- request:
method: get
uri: http://maps.googleapis.com/maps/api/geocode/json?address=Miami,%20FL&language=en&sensor=false
body:
encoding: US-ASCII
string: ''
headers:
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept:
- ! '*/*'
User-Agent:
- Ruby
It's the same URL and very same request, shouldn't VCR stub the request? How can I prevent my specs from hitting the API every time I try to search for the same city?
Upvotes: 12
Views: 7304
Reputation: 2620
Using Elasticsearch with VCR will always regenerate the cassettes if you not define the match parameters. I've to define the match to only :method
because the :uri
and :body
could change each time that the test is running.
VCR.configure do |c|
c.hook_into :webmock
c.ignore_localhost = true
c.configure_rspec_metadata!
c.cassette_library_dir = 'spec/cassettes'
c.default_cassette_options = { record: :new_episodes,
match_requests_on: [:method] }
end
Upvotes: 0
Reputation: 656
When I had a similar problem, I fixed it by making the match_requests_on setting more specific:
VCR.configure do |c|
c.default_cassette_options = {
match_requests_on: [:uri, :body, :method]
}
end
Upvotes: 10
Reputation: 21810
It's hard to say for sure what's going on with just what you've posted, but I can explain a bit more about how VCR works and make some guesses about possible reasons for this behavior.
VCR uses request matchers to try to find a previously recorded HTTP interaction to play back. During a single cassette session, when an HTTP interaction is played back, it is considered to be "used" and it will not be played back again (unless you use the allow_playback_repeats option).
So...here are a couple possibilities that come to mind:
:allow_playback_repeats
(which is the default, and how I recommend you use VCR), then the behavior you're seeing could happen if multiple duplicate requests are being made in your test--e.g., maybe the cassette has only one matching request but you're test makes 2 of them--that would play back one and record one (since you're using :new_episodes
).To troubleshoot this, I recommend you use the debug_logger option to get VCR to print what it's doing and how it's trying to match each request. That should give you insight into what's going on. You can also override any of the built in request matchers and provide your own logic and/or set a breakpoint in the matcher:
VCR.configure do |c|
c.register_request_matcher :uri do |request_1, request_2|
debugger # so you can inspect the requests here
request_1.uri == request_2.uri
end
end
You may also have run into a VCR bug, although comparing the URIs (using String#==
) is such a basic operation that I have a hard time imagining a bug there. Feel free to open a github issue (hopefully with the debug logger output and/or a code sample that triggers this) if you can't figure it out.
On a side note, I recommend you use the :once
record mode (the default) rather than :new_episodes
. :once
will never record additional HTTP interactions to an existing cassette--it only allows the cassette to be recorded once. If a request fails to match, it'll raise an error alerting you to the fact it couldn't match. :new_episodes
, on the other hand, will record any request that it can't find a match for, which is the behavior you're seeing.
Upvotes: 21
Reputation: 30434
I experienced similar behaviour, so what I do is basically keeping to set to :none
. If any new requests come up, I use :any
, run the part of the test suite that did the requests and set it back to :none
.
Seems like :new_episodes
uses some strange heuristics to detemermine what new requests are and what requests already occurred. In our case it marked two different requests to the payment gateways as the same ones, leading to endless hours of debugging - because we got a RefundOk
answer to a CaptureRequest
and things like that. Better don't use :new_episodes
...
Upvotes: 2