Rack::VCR
Rack::VCR captures incoming HTTP requests and responses on your Rack application (Rails, Sinatra) and saves them as a VCR fixture in cassettes.
Installation
Add this line to your application's Gemfile:
gem 'rack-vcr'
And then execute:
$ bundle
Or install it yourself as:
$ gem install rack-vcr
Usage
Capturing in Rails
In config/initializers/rack_vcr.rb
:
if Rails.env.test?
Rails.configuration.middleware.insert(0, Rack::VCR)
end
In spec/spec_helper.rb
:
VCR.configure do |config|
config.cassette_library_dir = 'doc/cassettes'
end
RSpec.configure do |config|
config.around(:each, type: :request) do |example|
host! "yourapp.hostname"
name = example.full_description.gsub /[^\w\-]/, '_'
VCR.use_cassette(name, record: :all) do
example.run
end
end
end
The above example might not work if you were using RSpec 2.x, in which case you might need to write as follows:
RSpec.configure do |config|
config.around(:each, type: :request) do |ex|
host! "yourapp.hostname"
name = example.full_description.gsub /[^\w\-]/, '_'
VCR.use_cassette(name, record: :all) do
ex.run
end
end
end
Read more about the changes around example
on RSpec blog post.
Capturing in Sinatra/Rack
In spec/spec_helper.rb
:
require 'rack/test'
VCR.configure do |config|
config.cassette_library_dir = "vcr_cassettes"
end
describe 'My Web App' do
include Rack::Test::Methods
let(:app) {
Rack::Builder.new do
use Rack::VCR
run Sinatra::Application
end
}
it 'runs the request' do
VCR.use_cassette('hello', record: :all) do
get "/hello"
end
# Now you get vcr_cassettes/hello.yml saved
end
end
Replaying
Rack::VCR also supports replaying recorded VCR cassettes. It means you can record the HTTP interactions with the real app (on CI), then use the cassette to run a fake/mock API server using Rack::VCR!
To replay cassettes, enable Rack::VCR with :replay
option in config.ru
or its equivalent.
VCR.configure do |config|
config.cassette_library_dir = "/path/to/cassettes"
end
Rack::Builder.new do
use Rack::VCR, replay: true,
cassette: "test", record: :new_episodes
run MyApp
end
With the above setting, Rack::VCR will try to locate the cassette named "test" to replay if the request matches with what's recorded, and fall through to the original application if it's not there. It also records the result to the cassette for further requests with the :record
option set to :new_episodes
.
You can set :record
option to :none
for example, to only serve what's already recorded in the cassette. The default value for :record
option is :new_episodes
.
To customize the cassette name in runtime, you can write a custom piece of Rack middleware around Rack::VCR to wrap the application in VCR.use_cassette
with its own :record
option.
class CassetteLocator
def initialize(app)
@app = app
end
def call(env)
cassette = ... # determine cassette from env
VCR.use_cassette(cassette, record: :none) do
@app.call(env)
end
end
end
Rack::Builder.new do
use CassetteLocator
use Rack::VCR, replay: true
run MyApp
end
Notes
There's a few similar gems available on Rubygems and GitHub:
- VCR::Middleware::Rack - Records outgoing HTTP requests inside a Rack application. Quite opposite to what Rack::VCR gem does.
- rack-recorder - Essentially the same with Rack::VCR, but is very limited in what it does. It doesn't export the captured transaction in VCR compatible format.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/miyagawa/rack-vcr.
Author
Tatsuhiko Miyagawa
License
The gem is available as open source under the terms of the MIT License.