Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but you can also compare across forks.

base fork: myronmarston/vcr
...
head fork: myronmarston/vcr
  • 7 commits
  • 17 files changed
  • 0 commit comments
  • 1 contributor
4 History.rdoc
View
@@ -1,3 +1,7 @@
+== 0.2.0 March 9, 2010
+* Added <tt>:allow_real_http</tt> cassette option, which allows VCR to work with capybara and a javascript driver.
+ Bug reported by {Ben Hutton}[http://github.com/benhutton].
+* Deprecated the default_cassette_record_mode option. Use default_cassette_options instead.
== 0.1.2 March 4, 2010
* Added explanatory note about VCR to FakeWeb::NetConnectNotAllowedError#message.
33 README.rdoc
View
@@ -69,8 +69,11 @@ modes are:
# the cache_dir is where the cassette yml files will be saved.
c.cache_dir = File.join(Rails.root, 'features', 'fixtures', 'vcr_cassettes')
- # this record mode will be used for any cassette you create without specifying a record mode.
- c.default_cassette_record_mode = :none
+ # these options will be used as defaults for your cassettes, but you can override them in each individual cassette.
+ c.default_cassette_options = {
+ :record => :none,
+ :allow_real_http => :localhost
+ }
end
This can go pretty much wherever, as long as this code is run before your tests, specs or scenarios. I tend
@@ -101,6 +104,27 @@ Alternately, you can create and destroy the cassette with individual method call
In both of these cases, VCR would use the file geocoding/Seattle_WA.yml within the configured
cache dir. The :record setting is optional--if you leave it blank, your configured default will be used.
+Besides the :record option, cassettes also support the :allow_real_http option. You can use this to make the cassette
+allow some real HTTP requests. You can specify it with a lambda:
+
+ VCR.with_cassette('my cassette', :allow_real_http => lambda { |uri| uri.host == 'google.com' }) do
+ # do something that causes an HTTP request.
+ end
+
+In this case, any google HTTP requests will be made for real, regardless of your <tt>FakeWeb.allow_net_connect</tt> setting,
+your current record mode, and whether or not you are recording or replaying this cassette. Non-google requests will do
+the appropriate recording/replaying as usual. You can also use the special <tt>:localhost</tt> option:
+
+ VCR.with_cassette('my cassette', :allow_real_http => :localhost) do
+ # do something that causes an HTTP request.
+ end
+
+This is equivalent to using a lambda like:
+
+ lambda { |uri| uri.host == 'localhost' }
+
+This is needed for using VCR with {capybara}[http://github.com/jnicklas/capybara] and any of the javascript drivers (see below for more info).
+
== Usage with Cucumber
VCR provides special support for cucumber. You can of course use <tt>VCR.with_cassette</tt> within a step definition,
@@ -125,6 +149,11 @@ For each of the tags you specify in your cucumber_tags block, VCR will set up th
for the entire scenario. The tag (minus the '@') will be used as the cassette name, and it'll
go in the cucumber_tags subdirectory of the configured cache dir.
+== Usage with Capybara
+
+When you use any of the javascript-enabled drivers (selenium, celerity, culerity) with {capybara}[http://github.com/jnicklas/capybara],
+it'll need to ping the app running on localhost. You can use the <tt>:allow_real_http => :localhost</tt> option to allow this.
+
== Suggested Workflow
First, configure VCR and FakeWeb as I have above. I like setting <tt>FakeWeb.allow_net_connect</tt> to <tt>false</tt>
2  VERSION
View
@@ -1 +1 @@
-0.1.2
+0.2.0
6 features/record_response.feature
View
@@ -64,3 +64,9 @@ Feature: Record response
When I make a recursive HTTP post request to "http://example.com" within the "temp/recursive_post" unregistered cassette
Then the "temp/recursive_post" cache file should have a response for "http://example.com" that matches /You have reached this web page by typing.*example\.com/
And the "temp/recursive_post" cache file should have exactly 1 response
+
+ Scenario: Make an allowed HTTP request in a cassette with record mode set to :none
+ Given we do not have a "temp/record_none_cassette" cassette
+ When I make an HTTP get request to "http://example.com" within the "temp/record_none_cassette" none cassette, allowing requests matching /example.com/
+ Then the response for "http://example.com" should match /You have reached this web page by typing.*example\.com/
+ And there should not be a "temp/record_none_cassette" cache file
8 features/step_definitions/vcr_steps.rb
View
@@ -67,11 +67,11 @@ def recorded_responses_for(cassette_name)
@http_requests[url] += [result]
end
-When /^I make(?: an)?(.*)? HTTP (get|post) requests? to "([^\"]*)"(?: and "([^\"]*)")? within the "([^\"]*)" ?(#{VCR::Cassette::VALID_RECORD_MODES.join('|')})? cassette$/ do |request_type, method, url1, url2, cassette_name, record_mode|
- record_mode ||= :unregistered
- record_mode = record_mode.to_sym
+When /^I make(?: an)?(.*)? HTTP (get|post) requests? to "([^\"]*)"(?: and "([^\"]*)")? within the "([^\"]*)" ?(#{VCR::Cassette::VALID_RECORD_MODES.join('|')})? cassette(?:, allowing requests matching \/([^\/]+)\/)?$/ do |request_type, method, url1, url2, cassette_name, record_mode, allowed|
+ options = { :record => (record_mode ? record_mode.to_sym : :unregistered) }
+ options[:allow_real_http] = lambda { |uri| uri.to_s =~ /#{allowed}/ } if allowed.to_s.size > 0
urls = [url1, url2].select { |u| u.to_s.size > 0 }
- VCR.with_cassette(cassette_name, :record => record_mode) do
+ VCR.with_cassette(cassette_name, options) do
urls.each do |url|
When %{I make an#{request_type} HTTP #{method} request to "#{url}"}
end
15 lib/vcr/cassette.rb
View
@@ -9,7 +9,8 @@ class Cassette
def initialize(name, options = {})
@name = name
- @record_mode = options[:record] || VCR::Config.default_cassette_record_mode
+ @record_mode = options[:record] || VCR::Config.default_cassette_options[:record]
+ @allow_real_http_lambda = allow_real_http_lambda_for(options[:allow_real_http] || VCR::Config.default_cassette_options[:allow_real_http])
self.class.raise_error_unless_valid_record_mode(record_mode)
set_fakeweb_allow_net_connect
load_recorded_responses
@@ -39,6 +40,10 @@ def self.raise_error_unless_valid_record_mode(record_mode)
end
end
+ def allow_real_http_requests_to?(uri)
+ @allow_real_http_lambda ? @allow_real_http_lambda.call(uri) : false
+ end
+
private
def new_recorded_responses
@@ -93,5 +98,13 @@ def deregister_original_recorded_responses
FakeWeb.remove_from_registry(rr.method, rr.uri)
end
end
+
+ def allow_real_http_lambda_for(allow_option)
+ if allow_option == :localhost
+ lambda { |uri| uri.host == 'localhost' }
+ else
+ allow_option
+ end
+ end
end
end
12 lib/vcr/config.rb
View
@@ -9,10 +9,14 @@ def cache_dir=(cache_dir)
FileUtils.mkdir_p(cache_dir) if cache_dir
end
- attr_reader :default_cassette_record_mode
- def default_cassette_record_mode=(default_cassette_record_mode)
- VCR::Cassette.raise_error_unless_valid_record_mode(default_cassette_record_mode)
- @default_cassette_record_mode = default_cassette_record_mode
+ attr_writer :default_cassette_options
+ def default_cassette_options
+ @default_cassette_options ||= {}
+ end
+
+ def default_cassette_record_mode=(value)
+ warn %Q{WARNING: #default_cassette_record_mode is deprecated. Instead, use: "default_cassette_options = { :record => :#{value.to_s} }"}
+ default_cassette_options.merge!(:record => value)
end
end
end
10 lib/vcr/extensions/fake_web.rb
View
@@ -5,6 +5,16 @@ def self.remove_from_registry(method, url)
Registry.instance.remove(method, url)
end
+ def self.with_allow_net_connect_set_to(value)
+ original_value = FakeWeb.allow_net_connect?
+ begin
+ FakeWeb.allow_net_connect = value
+ yield
+ ensure
+ FakeWeb.allow_net_connect = original_value
+ end
+ end
+
class Registry #:nodoc:
def remove(method, url)
uri_map.delete_if do |uri, method_hash|
41 lib/vcr/extensions/net_http.rb
View
@@ -4,9 +4,14 @@ module Net
class HTTP
def request_with_vcr(request, body = nil, &block)
@__request_with_vcr_call_count = (@__request_with_vcr_call_count || 0) + 1
- response = request_without_vcr(request, body, &block)
- __store_response_with_vcr__(response, request) if @__request_with_vcr_call_count == 1
- response
+ uri = URI.parse(__vcr_uri__(request))
+ if (cassette = VCR.current_cassette) && cassette.allow_real_http_requests_to?(uri)
+ FakeWeb.with_allow_net_connect_set_to(true) { request_without_vcr(request, body, &block) }
+ else
+ response = request_without_vcr(request, body, &block)
+ __store_response_with_vcr__(response, request) if @__request_with_vcr_call_count == 1
+ response
+ end
ensure
@__request_with_vcr_call_count -= 1
end
@@ -15,22 +20,26 @@ def request_with_vcr(request, body = nil, &block)
private
- def __store_response_with_vcr__(response, request)
- if cassette = VCR.current_cassette
- # Copied from: http://github.com/chrisk/fakeweb/blob/fakeweb-1.2.8/lib/fake_web/ext/net_http.rb#L39-52
- protocol = use_ssl? ? "https" : "http"
+ def __vcr_uri__(request)
+ # Copied from: http://github.com/chrisk/fakeweb/blob/fakeweb-1.2.8/lib/fake_web/ext/net_http.rb#L39-52
+ protocol = use_ssl? ? "https" : "http"
- path = request.path
- path = URI.parse(request.path).request_uri if request.path =~ /^http/
+ path = request.path
+ path = URI.parse(request.path).request_uri if request.path =~ /^http/
- if request["authorization"] =~ /^Basic /
- userinfo = FakeWeb::Utility.decode_userinfo_from_header(request["authorization"])
- userinfo = FakeWeb::Utility.encode_unsafe_chars_in_userinfo(userinfo) + "@"
- else
- userinfo = ""
- end
+ if request["authorization"] =~ /^Basic /
+ userinfo = FakeWeb::Utility.decode_userinfo_from_header(request["authorization"])
+ userinfo = FakeWeb::Utility.encode_unsafe_chars_in_userinfo(userinfo) + "@"
+ else
+ userinfo = ""
+ end
- uri = "#{protocol}://#{userinfo}#{self.address}:#{self.port}#{path}"
+ "#{protocol}://#{userinfo}#{self.address}:#{self.port}#{path}"
+ end
+
+ def __store_response_with_vcr__(response, request)
+ if cassette = VCR.current_cassette
+ uri = __vcr_uri__(request)
method = request.method.downcase.to_sym
unless FakeWeb.registered_uri?(method, uri)
55 spec/cassette_spec.rb
View
@@ -1,19 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
describe VCR::Cassette do
- before(:all) do
- @orig_default_cassette_record_mode = VCR::Config.default_cassette_record_mode
- VCR::Config.default_cassette_record_mode = :unregistered
- end
-
- after(:all) do
- VCR::Config.default_cassette_record_mode = :unregistered
- end
-
- before(:each) do
- FakeWeb.clean_registry
- end
-
describe '#cache_file' do
temp_dir File.expand_path(File.dirname(__FILE__) + '/fixtures/cache_file'), :assign_to_cache_dir => true
@@ -55,8 +42,8 @@
end
VCR::Cassette::VALID_RECORD_MODES.each do |mode|
- it "defaults the record mode to #{mode} when VCR::Config.default_cassette_record_mode is #{mode}" do
- VCR::Config.default_cassette_record_mode = mode
+ it "defaults the record mode to #{mode} when VCR::Config.default_cassette_options[:record] is #{mode}" do
+ VCR::Config.default_cassette_options = { :record => mode }
cassette = VCR::Cassette.new(:test)
cassette.record_mode.should == mode
end
@@ -116,6 +103,44 @@
end
end
+ describe '#allow_real_http_requests_to?' do
+ it 'delegates to the :allow_real_http lambda' do
+ [true, false].each do |value|
+ yielded_uri = nil
+ c = VCR::Cassette.new('example', :allow_real_http => lambda { |uri| yielded_uri = uri; value })
+ c.allow_real_http_requests_to?(:the_uri).should == value
+ yielded_uri.should == :the_uri
+ end
+ end
+
+ it 'returns true for localhost requests when the :allow_real_http option is set to :localhost' do
+ c = VCR::Cassette.new('example', :allow_real_http => :localhost)
+ c.allow_real_http_requests_to?(URI('http://localhost')).should be_true
+ c.allow_real_http_requests_to?(URI('http://example.com')).should be_false
+ end
+
+ it 'returns false when no option is set' do
+ c = VCR::Cassette.new('example')
+ c.allow_real_http_requests_to?(URI('http://localhost')).should be_false
+ c.allow_real_http_requests_to?(URI('http://example.com')).should be_false
+ end
+
+ it 'delegates to the default :allow_real_http lambda' do
+ [true, false].each do |value|
+ yielded_uri = nil
+ VCR::Config.default_cassette_options.merge!(:allow_real_http => lambda { |uri| yielded_uri = uri; value })
+ c = VCR::Cassette.new('example')
+ c.allow_real_http_requests_to?(:the_uri).should == value
+ yielded_uri.should == :the_uri
+ end
+
+ VCR::Config.default_cassette_options.merge!(:allow_real_http => :localhost)
+ c = VCR::Cassette.new('example')
+ c.allow_real_http_requests_to?(URI('http://localhost')).should be_true
+ c.allow_real_http_requests_to?(URI('http://example.com')).should be_false
+ end
+ end
+
describe '#destroy!' do
temp_dir File.expand_path(File.dirname(__FILE__) + '/fixtures/cassette_spec_destroy'), :assign_to_cache_dir => true
32 spec/config_spec.rb
View
@@ -13,15 +13,35 @@
end
end
- describe '#default_cassette_record_mode' do
- VCR::Cassette::VALID_RECORD_MODES.each do |mode|
- it "allows #{mode}" do
- lambda { VCR::Config.default_cassette_record_mode = mode }.should_not raise_error
+ describe '#default_cassette_options' do
+ it 'always has a hash, even if it is set to nil' do
+ VCR::Config.default_cassette_options = nil
+ VCR::Config.default_cassette_options.should == {}
+ end
+ end
+
+ describe '#default_cassette_record_mode=' do
+ disable_warnings
+
+ it 'sets the default_cassette_options[:record] option' do
+ VCR::Cassette::VALID_RECORD_MODES.each do |mode|
+ VCR::Config.default_cassette_options = nil
+ VCR::Config.default_cassette_record_mode = mode
+ VCR::Config.default_cassette_options[:record].should == mode
end
end
- it "does not allow :not_a_record_mode" do
- lambda { VCR::Config.default_cassette_record_mode = :not_a_record_mode }.should raise_error(ArgumentError)
+ it 'merges the :record option with the existing default_cassette_record options' do
+ VCR::Config.default_cassette_options = { :an => :option }
+ VCR::Config.default_cassette_record_mode = :all
+ VCR::Config.default_cassette_options.should == { :an => :option, :record => :all }
+ end
+
+ it 'warns the user that it is deprecated' do
+ VCR::Cassette::VALID_RECORD_MODES.each do |mode|
+ VCR::Config.should_receive(:warn).with(%Q{WARNING: #default_cassette_record_mode is deprecated. Instead, use: "default_cassette_options = { :record => :#{mode.to_s} }"})
+ VCR::Config.default_cassette_record_mode = mode
+ end
end
end
end
30 spec/extensions/fake_web_spec.rb
View
@@ -30,4 +30,34 @@
'The fakeweb error message. You can use VCR to automatically record this request and replay it later with fakeweb. For more details, see the VCR README at: http://github.com/myronmarston/vcr'
end
end
+
+ describe "#with_allow_net_connect_set_to" do
+ it 'sets allow_net_connect for the duration of the block to the provided value' do
+ [true, false].each do |expected|
+ yielded_value = :not_set
+ FakeWeb.with_allow_net_connect_set_to(expected) { yielded_value = FakeWeb.allow_net_connect? }
+ yielded_value.should == expected
+ end
+ end
+
+ it 'returns the value returned by the block' do
+ FakeWeb.with_allow_net_connect_set_to(true) { :return_value }.should == :return_value
+ end
+
+ it 'reverts allow_net_connect when the block completes' do
+ [true, false].each do |expected|
+ FakeWeb.allow_net_connect = expected
+ FakeWeb.with_allow_net_connect_set_to(true) { }
+ FakeWeb.allow_net_connect?.should == expected
+ end
+ end
+
+ it 'reverts allow_net_connect when the block completes, even if an error is raised' do
+ [true, false].each do |expected|
+ FakeWeb.allow_net_connect = expected
+ lambda { FakeWeb.with_allow_net_connect_set_to(true) { raise RuntimeError } }.should raise_error(RuntimeError)
+ FakeWeb.allow_net_connect?.should == expected
+ end
+ end
+ end
end
66 spec/extensions/net_http_spec.rb
View
@@ -1,45 +1,57 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "Net::HTTP Extensions" do
- before(:all) do
- @orig_allow_net_connect = FakeWeb.allow_net_connect?
- FakeWeb.allow_net_connect = true
+ before(:each) do
+ VCR.stub!(:current_cassette).and_return(@current_cassette = mock)
+ @uri = URI.parse('http://example.com')
end
- after(:all) do
- FakeWeb.allow_net_connect = @orig_allow_net_connect
+ it 'works when there is no current cassette' do
+ VCR.stub!(:current_cassette).and_return(nil)
+ lambda { Net::HTTP.get(@uri) }.should_not raise_error
end
- before(:each) do
- @current_cassette = mock
- VCR.stub!(:current_cassette).and_return(@current_cassette)
- FakeWeb.clean_registry
- end
-
- describe 'a request that is not registered with FakeWeb' do
- it 'calls #store_recorded_response! on the current cassette' do
- recorded_response = VCR::RecordedResponse.new(:get, 'http://example.com:80/', :example_response)
- VCR::RecordedResponse.should_receive(:new).with(:get, 'http://example.com:80/', an_instance_of(Net::HTTPOK)).and_return(recorded_response)
- @current_cassette.should_receive(:store_recorded_response!).with(recorded_response)
- Net::HTTP.get(URI.parse('http://example.com'))
+ context 'when current_cassette.allow_real_http_requests_to? returns false' do
+ before(:each) do
+ @current_cassette.should_receive(:allow_real_http_requests_to?).at_least(:once).with(@uri).and_return(false)
end
- it 'calls #store_recorded_response! only once, even when Net::HTTP internally recursively calls #request' do
- @current_cassette.should_receive(:store_recorded_response!).once
- Net::HTTP.new('example.com', 80).post('/', nil)
+ describe 'a request that is not registered with FakeWeb' do
+ it 'calls #store_recorded_response! on the current cassette' do
+ recorded_response = VCR::RecordedResponse.new(:get, 'http://example.com:80/', :example_response)
+ VCR::RecordedResponse.should_receive(:new).with(:get, 'http://example.com:80/', an_instance_of(Net::HTTPOK)).and_return(recorded_response)
+ @current_cassette.should_receive(:store_recorded_response!).with(recorded_response)
+ Net::HTTP.get(@uri)
+ end
+
+ it 'calls #store_recorded_response! only once, even when Net::HTTP internally recursively calls #request' do
+ @current_cassette.should_receive(:store_recorded_response!).once
+ Net::HTTP.new('example.com', 80).post('/', nil)
+ end
end
- it 'does not have an error if there is no current cassette' do
- VCR.stub!(:current_cassette).and_return(nil)
- lambda { Net::HTTP.get(URI.parse('http://example.com')) }.should_not raise_error
+ describe 'a request that is registered with FakeWeb' do
+ it 'does not call #store_recorded_response! on the current cassette' do
+ FakeWeb.register_uri(:get, 'http://example.com', :body => 'example.com response')
+ @current_cassette.should_not_receive(:store_recorded_response!)
+ Net::HTTP.get(@uri)
+ end
end
end
- describe 'a request that is registered with FakeWeb' do
+ context 'when current_cassette.allow_real_http_requests_to? returns true' do
+ before(:each) do
+ @current_cassette.should_receive(:allow_real_http_requests_to?).with(@uri).and_return(true)
+ end
+
it 'does not call #store_recorded_response! on the current cassette' do
- FakeWeb.register_uri(:get, 'http://example.com', :body => 'example.com response')
- @current_cassette.should_not_receive(:store_recorded_response!)
- Net::HTTP.get(URI.parse('http://example.com'))
+ @current_cassette.should_receive(:store_recorded_response!).never
+ Net::HTTP.get(@uri)
+ end
+
+ it 'uses FakeWeb.with_allow_net_connect_set_to(true) to make the request' do
+ FakeWeb.should_receive(:with_allow_net_connect_set_to).with(true).and_yield
+ Net::HTTP.get(@uri)
end
end
end
7 spec/spec_helper.rb
View
@@ -19,4 +19,11 @@
Spec::Runner.configure do |config|
config.extend TempCacheDir
+ config.extend DisableWarnings
+
+ config.before(:each) do
+ VCR::Config.default_cassette_options = { :record => :unregistered }
+ FakeWeb.allow_net_connect = true
+ FakeWeb.clean_registry
+ end
end
12 spec/support/disable_warnings.rb
View
@@ -0,0 +1,12 @@
+module DisableWarnings
+ def disable_warnings
+ before(:all) do
+ @orig_std_err = $stderr
+ $stderr = StringIO.new
+ end
+
+ after(:all) do
+ $stderr = @orig_std_err
+ end
+ end
+end
9 spec/vcr_spec.rb
View
@@ -1,15 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
describe VCR do
- before(:all) do
- @orig_default_cassette_record_mode = VCR::Config.default_cassette_record_mode
- VCR::Config.default_cassette_record_mode = :unregistered
- end
-
- after(:all) do
- VCR::Config.default_cassette_record_mode = :unregistered
- end
-
def create_cassette
VCR.create_cassette!(:cassette_test)
end
6 vcr.gemspec
View
@@ -5,11 +5,11 @@
Gem::Specification.new do |s|
s.name = %q{vcr}
- s.version = "0.1.2"
+ s.version = "0.2.0"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Myron Marston"]
- s.date = %q{2010-03-04}
+ s.date = %q{2010-03-09}
s.description = %q{VCR provides helpers to record HTTP requests for URIs that are not registered with fakeweb, and replay them later. It provides built-in support for cucumber, but works with any ruby testing framework.}
s.email = %q{myron.marston@gmail.com}
s.extra_rdoc_files = [
@@ -63,6 +63,7 @@ Gem::Specification.new do |s|
"spec/recorded_response_spec.rb",
"spec/spec.opts",
"spec/spec_helper.rb",
+ "spec/support/disable_warnings.rb",
"spec/support/temp_cache_dir.rb",
"spec/vcr_spec.rb",
"vcr.gemspec"
@@ -81,6 +82,7 @@ Gem::Specification.new do |s|
"spec/extensions/net_read_adapter_spec.rb",
"spec/recorded_response_spec.rb",
"spec/spec_helper.rb",
+ "spec/support/disable_warnings.rb",
"spec/support/temp_cache_dir.rb",
"spec/vcr_spec.rb"
]

No commit comments for this range

Something went wrong with that request. Please try again.