VCR Gem: Custom Matchers
Using custom matchers to help with the dreaded "VCR::Errors::UnhandledHTTPRequestError"
I can't say enough good things about the VCR Gem. I use it profusely when performing a QuickBooks & Ruby integration project. Recently, there was a situation where the quickbooks-ruby Gem had a slight change to the base API URI. The change caused one of my client's 30+ QuickBooks VCR-related specs to fail. I knew about custom matchers having already implemented one that disregards a trailing numeric id on a given URI. However, with this current problem I didn't want to have to add a { match_requests_on: [:method, :custom_matcher_name]
to each of the existing failing cassettes. I wanted a global solution, preferably in my VCR.configure
block that would handle this alteration in the quickbooks-ruby library. Come watch how the problem got solved and learn a bit more about custom matchers.
.. [a small library change] resulted in my client's 30+ VCR related specs to fail.
- To solve this issue I am going to leverage the VCR configure option
default_cassette_options
. - Next, I investigate the output of
uri1
anduri2
by running one of the problem specs. - At least both URIs have
intuit.com
in common so I can safely filter old and new cassettes by matching against it. - So I decide to just remove the
quickbooks.api
and theqb.sbfinance
. That leaves me with a more permissive matcher, which is strict enough to keep my VCR enabled specs honest. - Next, I add the substituted URIs to the
uri_matcher
and the spec passes. - Remember again, by using
default_cassette_options
that this matcher will run on every VCR cassette. - I also rolled in a previous custom matcher,
uri_ignore_trailing_id
, within the new custom matcher. - This is because setting individual cassettes with
match_requests_on
will result in thedefault_cassette_options
being overridden. Therefore, VCR specs marked with an existing matcher such asuri_ignore_trailing_id
will still not pass, hence the previous step of moving theuri_ignore_trailing_id
matcher inside of thefor_intuit
matcher.
Be aware that default_cassette_options
will be run on each of your existing and future cassettes. I am going use this feature to filter out all cassettes that have request calls to intuit.com. Within that conditional block I am going to have all of my matching logic for QuickBooks specs. This will eliminate having to laboriously put 'match_requests_on' options to each individual cassette.
See figure to aid my description.
Now that I am globally filtering out all cassettes with requests to intuit.com, I now need to fix the UnhandledHTTPRequestError. While I go about doing that I need to be concerned about making the matcher too lenient. If the custom matcher is not stringent enough it will make my QuickBooks specs prone to errors. I need to strive to make the matcher disregard only the difference between the quickbooks.api
and the qb.sbfinance
and not the rest of the URI.
That concludes Custom matchers in VCR
This should give you a good starting point on how to create your own custom matchers. Be sure to view the screencast to get some more in depth commentary if this article is not clear enough. Finally, I want to give thanks to Myron Marston, the creator of VCR, for aiding me in this solution by answering my SO question.
Thanks for putting this together!
It's nice to have a screencast that shows how to use one of the more "power user" features of VCR.
For your particular use case, I'd actually recommend using a different VCR feature to solve it: define_cassette_placeholder
:
Here's an example of it being used:
In your case, you could do something like:
VCR.configure do |c| c.define_cassette_placeholder("<quickbooks_host>") do QuickBooks.host # or whatever constant or config setting exposes the host end end
When the cassettes are recorded, it'll put <quickbooks_host>
in place of the real host name as a variable, and then during playback, it'll replace the variable, with current value returned by the block. This will allow it to continue to work whenever the host changes.
- Pushed on 07/28/2014 by Christian