Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Upgrade to Capybara 2. Fixes forms and redirects. #44

Merged
merged 6 commits into from

5 participants

Ryan Schlesinger Nick Morgan Jeroen van Dijk Phill Baker aaronchi
Ryan Schlesinger

This replaces #37 and #43.

There are quite a lot of changes to bring capybara-mechanize up to capybara 2. The test suite has had an overhaul to become compatible.

The entire capybara 2 session test passes both in rack-test mode (local) and in mechanize mode (remote) with 2 exceptions.

  1. Returning exceptions from the app under test: When we're running against a remote server, we're no longer sending requests directly to the app under test. We want to return errors we received over the wire.

  2. Sending requests to the app under test without a port number: When we're running against a remote server, not specifying the port is the same as hitting port 80. The test doesn't make any sense in this case.

Note that both of those tests pass in the local case.

Ryan Schlesinger

This should also close #25 and #26.

Ryan Schlesinger

I just pushed a change that disables the aforementioned two failing tests when running the remote tests. The test suite is now green.

Ryan Schlesinger

Ruby 1.8.7 doesn't like my use of define_method. I'll get to that in a bit.

Ryan Schlesinger

Ahh. Capybara 2.0 and up doesn't support 1.8.7. I'm going to drop support in this branch as well.

Ryan Schlesinger

@phillbaker I think this is ready now.

Ryan Schlesinger

@phillbaker We're also going to need a version bump when this is accepted to mark a break in compatibility.

Jeroen van Dijk

@phillbaker I need your (rubygems) email address so I can add you as owner for this gem at rubygems

Phill Baker
Collaborator

@ryasnsch, thanks a ton for all of your work. This looks very good, let me review and make sure, but it's very promising!

@jeroenvandijk thanks, that'd be helpful. I'm at phillbaker@retrodict.com, on rubygems at http://rubygems.org/profiles/phillbaker.

Jeroen van Dijk

@phillbaker I've added you as gem owner see http://rubygems.org/profiles/phillbaker . Thanks for getting involved :)

Phill Baker phillbaker merged commit 56f6ab7 into from
Phill Baker
Collaborator

Again @ryansch, thanks for the work and involvement. I'll be bumping the version and releasing a preview.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
6 .travis.yml
View
@@ -4,9 +4,11 @@ before_install:
- gem update --system
- gem --version
rvm:
- - 1.8.7
- - ree
- 1.9.3
- rbx-19mode
- jruby-19mode
- ruby-head
+matrix:
+ allow_failures:
+ - rvm: jruby-19mode
+ - rvm: ruby-head
4 capybara-mechanize.gemspec
View
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
s.require_paths = ["lib"]
s.rubygems_version = %q{1.3.7}
- s.add_runtime_dependency(%q<mechanize>, ["~> 2.3"])
- s.add_runtime_dependency(%q<capybara>, ["~> 1.1"])
+ s.add_runtime_dependency(%q<mechanize>, ["~> 2.5"])
+ s.add_runtime_dependency(%q<capybara>, ["~> 2.0", ">= 2.0.1"])
end
116 lib/capybara/mechanize/browser.rb
View
@@ -1,5 +1,7 @@
require 'capybara/rack_test/driver'
require 'mechanize'
+require 'capybara/mechanize/node'
+require 'capybara/mechanize/form'
class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
extend Forwardable
@@ -28,81 +30,22 @@ def last_response
last_request_remote? ? remote_response : super
end
- # process should be maintained as a direct copy of the base class's version with the addition of the marked line below
- def process(method, path, attributes = {})
- new_uri = URI.parse(path)
- current_uri = URI.parse(current_url)
+ # For each of these http methods, we want to intercept the method call.
+ # Then we determine if the call is remote or local.
+ # Remote: Handle it with our process_remote_request method.
+ # Local: Register the local request and call super to let RackTest get it.
+ [:get, :post, :put, :delete].each do |method|
+ define_method(method) do |path, params = {}, env = {}, &block|
+ path = @last_path if path.nil? || path.empty?
- if new_uri.host
- @current_host = new_uri.scheme + '://' + new_uri.host
-
- # The process method has only been reimplemented in this derived class for this one line.
- # Note that this line is copied directly from capybara pre-2.0
- @current_host << ":#{new_uri.port}" if new_uri.port != new_uri.default_port
- end
-
- if new_uri.relative?
- if path.start_with?('?')
- path = request_path + path
- elsif not path.start_with?('/')
- path = request_path.sub(%r(/[^/]*$), '/') + path
+ if remote?(path)
+ process_remote_request(method, path, params, env, &block)
+ else
+ register_local_request
+ super(path, params, env, &block)
end
- path = current_host + path
- end
-
- reset_cache!
- send(method, path, attributes, env)
- end
-
- def process_without_redirect(method, path, attributes, headers)
- path = @last_path if path.nil? || path.empty?
- if remote?(path)
- process_remote_request(method, path, attributes, headers)
- else
- register_local_request
-
- send("racktest_#{method}", path, attributes, env.merge(headers))
- end
-
- @last_path = path
- end
-
- alias :racktest_get :get
- def get(path, attributes = {}, headers = {})
- process_without_redirect(:get, path, attributes, headers)
- end
-
- alias :racktest_post :post
- def post(path, attributes = {}, headers = {})
- process_without_redirect(:post, path, post_data(attributes), headers)
- end
-
- alias :racktest_put :put
- def put(path, attributes = {}, headers = {})
- process_without_redirect(:put, path, attributes, headers)
- end
-
- alias :racktest_delete :delete
- def delete(path, attributes = {}, headers = {})
- process_without_redirect(:delete, path, attributes, headers)
- end
-
- def post_data(params)
- params.inject({}) do |memo, param|
- case param
- when Hash
- param.each {|attribute, value| memo[attribute] = value }
- memo
- when Array
- case param.last
- when Hash
- param.last.each {|attribute, value| memo["#{param.first}[#{attribute}]"] = value }
- else
- memo[param.first] = param.last
- end
- memo
- end
+ @last_path = path
end
end
@@ -120,6 +63,10 @@ def remote?(url)
end
end
+ def find(selector)
+ dom.xpath(selector).map { |node| Capybara::Mechanize::Node.new(self, node) }
+ end
+
attr_reader :agent
private
@@ -149,10 +96,22 @@ def process_remote_request(method, url, attributes, headers)
reset_cache!
begin
- args = []
- args << attributes unless attributes.empty?
- args << headers unless headers.empty?
- @agent.send(method, url, *args)
+ if method == :post
+ if attributes.is_a? Mechanize::Form
+ submit_mechanize_form(url, attributes, headers)
+ else
+ @agent.send(method, url, attributes, headers)
+ end
+ elsif method == :get
+ if attributes.is_a? Mechanize::Form
+ submit_mechanize_form(url, attributes, headers)
+ else
+ referer = headers['HTTP_REFERER']
+ @agent.send(method, url, attributes, referer, headers)
+ end
+ else
+ @agent.send(method, url, attributes, headers)
+ end
rescue => e
raise "Received the following error for a #{method.to_s.upcase} request to #{url}: '#{e.message}'"
end
@@ -160,6 +119,11 @@ def process_remote_request(method, url, attributes, headers)
end
end
+ def submit_mechanize_form(url, form, headers)
+ form.action = url
+ @agent.submit(form, nil, headers)
+ end
+
def remote_response
ResponseProxy.new(@agent.current_page) if @agent.current_page
end
8 lib/capybara/mechanize/driver.rb
View
@@ -2,12 +2,10 @@
class Capybara::Mechanize::Driver < Capybara::RackTest::Driver
- def initialize(app = nil, options = {})
- if !app && !Capybara.app_host
- raise ArgumentError, "You have to set at least Capybara.app_host or Capybara.app"
- end
+ def initialize(app, options = {})
+ raise ArgumentError, "mechanize requires a rack application, but none was given" unless app
- @app, @options = app, options
+ super
end
def remote?(url)
65 lib/capybara/mechanize/form.rb
View
@@ -0,0 +1,65 @@
+class Capybara::Mechanize::Form < Capybara::RackTest::Form
+
+ def params(button)
+ if !use_mechanize?
+ return super
+ end
+
+ node = {}
+ # Create a fake form
+ class << node
+ def search(*args); []; end
+ end
+ node['method'] = method.to_s.upcase
+
+ if self.multipart?
+ node['enctype'] = 'multipart/form-data'
+ else
+ node['enctype'] = 'application/x-www-form-urlencoded'
+ end
+
+ @m_form = Mechanize::Form.new(node, nil, form_referer)
+
+ super
+
+ @m_form
+ end
+
+ private
+
+ def merge_param!(params, key, value)
+ if !use_mechanize?
+ return super
+ end
+
+ if value.is_a? NilUploadedFile
+ # Adding a nil value here will result in the form element existing with the empty string as its value.
+ # Instead don't add the form element at all.
+ return params
+ end
+
+ if value.is_a? Rack::Test::UploadedFile
+ @m_form.enctype = 'multipart/form-data'
+
+ ul = Mechanize::Form::FileUpload.new({'name' => key.to_s}, value.original_filename)
+ ul.mime_type = value.content_type
+ ul.file_data = (value.rewind; value.read)
+
+ @m_form.file_uploads << ul
+
+ return params
+ end
+
+ @m_form.fields << Mechanize::Form::Field.new({'name' => key.to_s}, value)
+
+ params
+ end
+
+ def use_mechanize?
+ driver.remote?(native['action'].to_s)
+ end
+
+ def form_referer
+ Mechanize::Page.new URI(driver.current_url)
+ end
+end
10 lib/capybara/mechanize/node.rb
View
@@ -0,0 +1,10 @@
+class Capybara::Mechanize::Node < Capybara::RackTest::Node
+ def click
+ if tag_name == 'a'
+ super
+ elsif (tag_name == 'input' and %w(submit image).include?(type)) or
+ ((tag_name == 'button') and type.nil? or type == "submit")
+ Capybara::Mechanize::Form.new(driver, form).submit(self)
+ end
+ end
+end
18 lib/capybara/spec/extended_test_app.rb
View
@@ -36,10 +36,6 @@ class ExtendedTestApp < TestApp#< Sinatra::Base
current_request_info
end
- get '/host' do
- "Current host is #{request.scheme}://#{request.host}:#{request.port}"
- end
-
get '/subsite/relative_link_to_host' do
%{<a href="/subsite/request_info2/host">host</a>}
end
@@ -55,11 +51,23 @@ class ExtendedTestApp < TestApp#< Sinatra::Base
get '/redirect_with_http_param' do
redirect '/redirect_target?foo=http'
end
-
+
get '/redirect_target' do
%{correct redirect}
end
+ get %r{/form_posts_to/(.*)} do
+ %{
+ <form action="#{params[:captures].first}" method="post">
+ <input type="submit" value="submit" />
+ </form>
+ }
+ end
+
+ post '/get_referer' do
+ request.referer.nil? ? "No referer" : "Got referer: #{request.referer}"
+ end
+
private
def current_request_info
194 spec/driver/mechanize_driver_spec.rb
View
@@ -1,151 +1,215 @@
require 'spec_helper'
-describe "Capybara::Driver::Mechanize, in local model" do
- before do
- @driver = Capybara::Mechanize::Driver.new(ExtendedTestApp)
+describe Capybara::Mechanize::Driver, 'local' do
+ let(:driver) { Capybara::Mechanize::Driver.new(ExtendedTestApp) }
+
+ describe ':headers option' do
+ it 'should always set headers' do
+ driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'})
+ driver.visit('/get_header')
+ driver.html.should include('foobar')
+ end
+
+ it 'should keep headers on link clicks' do
+ driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'})
+ driver.visit('/header_links')
+ driver.find('.//a').first.click
+ driver.html.should include('foobar')
+ end
+
+ it 'should keep headers on form submit' do
+ driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'})
+ driver.visit('/header_links')
+ driver.find('.//input').first.click
+ driver.html.should include('foobar')
+ end
+
+ it 'should keep headers on redirects' do
+ driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'})
+ driver.visit('/get_header_via_redirect')
+ driver.html.should include('foobar')
+ end
+ end
+
+ describe ':follow_redirects option' do
+ it "defaults to following redirects" do
+ driver = Capybara::RackTest::Driver.new(TestApp)
+
+ driver.visit('/redirect')
+ driver.response.header['Location'].should be_nil
+ driver.browser.current_url.should match %r{/landed$}
+ end
+
+ it "is possible to not follow redirects" do
+ driver = Capybara::RackTest::Driver.new(TestApp, :follow_redirects => false)
+
+ driver.visit('/redirect')
+ driver.response.header['Location'].should match %r{/redirect_again$}
+ driver.browser.current_url.should match %r{/redirect$}
+ end
end
-
- it "should throw an error when no rack app is given without an app host" do
- running do
- Capybara::Mechanize::Driver.new
- end.should raise_error(ArgumentError, "You have to set at least Capybara.app_host or Capybara.app")
+
+ describe ':redirect_limit option' do
+ context "with default redirect limit" do
+ let(:driver) { Capybara::RackTest::Driver.new(TestApp) }
+
+ it "should follow 5 redirects" do
+ driver.visit("/redirect/5/times")
+ driver.html.should include('redirection complete')
+ end
+
+ it "should not follow more than 6 redirects" do
+ expect do
+ driver.visit("/redirect/6/times")
+ end.to raise_error(Capybara::InfiniteRedirectError)
+ end
+ end
+
+ context "with 21 redirect limit" do
+ let(:driver) { Capybara::RackTest::Driver.new(TestApp, :redirect_limit => 21) }
+
+ it "should follow 21 redirects" do
+ driver.visit("/redirect/21/times")
+ driver.html.should include('redirection complete')
+ end
+
+ it "should not follow more than 21 redirects" do
+ expect do
+ driver.visit("/redirect/22/times")
+ end.to raise_error(Capybara::InfiniteRedirectError)
+ end
+ end
end
-
- it_should_behave_like "driver"
- it_should_behave_like "driver with header support"
- it_should_behave_like "driver with status code support"
- it_should_behave_like "driver with cookies support"
- it_should_behave_like "driver with infinite redirect detection"
it "should default to local mode for relative paths" do
- @driver.should_not be_remote('/')
+ driver.should_not be_remote('/')
end
-
+
it "should default to local mode for the default host" do
- @driver.should_not be_remote('http://www.example.com')
+ driver.should_not be_remote('http://www.example.com')
end
context "with an app_host" do
-
+
before do
Capybara.app_host = 'http://www.remote.com'
end
-
+
after do
Capybara.app_host = nil
end
it "should treat urls as remote" do
- @driver.should be_remote('http://www.remote.com')
+ driver.should be_remote('http://www.remote.com')
end
end
context "with a default url, no app host" do
- before :each do
+ before do
Capybara.default_host = 'www.local.com'
end
-
+
it "should allow local hosts to be set" do
Capybara::Mechanize.local_hosts = ['subdomain.local.com']
- @driver.should_not be_remote('http://subdomain.local.com')
+ driver.should_not be_remote('http://subdomain.local.com')
end
-
+
it "should treat urls with the same host names as local" do
- @driver.should_not be_remote('http://www.local.com')
+ driver.should_not be_remote('http://www.local.com')
end
-
+
it "should treat other urls as remote" do
- @driver.should be_remote('http://www.remote.com')
+ driver.should be_remote('http://www.remote.com')
end
-
+
it "should treat relative paths as remote if the previous request was remote" do
- @driver.visit(REMOTE_TEST_URL)
- @driver.should be_remote('/some_relative_link')
+ driver.visit(REMOTE_TEST_URL)
+ driver.should be_remote('/some_relative_link')
end
it "should treat relative paths as local if the previous request was local" do
- @driver.visit('http://www.local.com')
- @driver.should_not be_remote('/some_relative_link')
+ driver.visit('http://www.local.com')
+ driver.should_not be_remote('/some_relative_link')
end
it "should receive the right host" do
- @driver.visit('http://www.local.com/host')
+ driver.visit('http://www.local.com/host')
should_be_a_local_get
end
it "should consider relative paths to be local when the previous request was local" do
- @driver.visit('http://www.local.com/host')
- @driver.visit('/host')
+ driver.visit('http://www.local.com/host')
+ driver.visit('/host')
should_be_a_local_get
- @driver.should_not be_remote('/first_local')
+ driver.should_not be_remote('/first_local')
end
-
+
it "should consider relative paths to be remote when the previous request was remote" do
- @driver.visit("#{REMOTE_TEST_URL}/host")
- @driver.get('/host')
+ driver.visit("#{REMOTE_TEST_URL}/host")
+ driver.get('/host')
should_be_a_remote_get
- @driver.should be_remote('/second_remote')
+ driver.should be_remote('/second_remote')
end
-
+
it "should always switch to the right context" do
- @driver.visit('http://www.local.com/host')
- @driver.get('/host')
- @driver.get("#{REMOTE_TEST_URL}/host")
- @driver.get('/host')
- @driver.get('http://www.local.com/host')
+ driver.visit('http://www.local.com/host')
+ driver.get('/host')
+ driver.get("#{REMOTE_TEST_URL}/host")
+ driver.get('/host')
+ driver.get('http://www.local.com/host')
should_be_a_local_get
- @driver.should_not be_remote('/second_local')
+ driver.should_not be_remote('/second_local')
end
it "should follow redirects from local to remote" do
- @driver.visit("http://www.local.com/redirect_to/#{REMOTE_TEST_URL}/host")
+ driver.visit("http://www.local.com/redirect_to/#{REMOTE_TEST_URL}/host")
should_be_a_remote_get
end
-
+
it "should follow redirects from remote to local" do
- @driver.visit("#{REMOTE_TEST_URL}/redirect_to/http://www.local.com/host")
+ driver.visit("#{REMOTE_TEST_URL}/redirect_to/http://www.local.com/host")
should_be_a_local_get
end
-
- after :each do
+
+ after do
Capybara.default_host = nil
end
-
+
it "should raise a useful error for sites that return a 404, because it is probably a misconfiguration" do
- lambda {
- @driver.visit("http://iamreallysurethatthisdoesntexist.com/canttouchthis")
- }.should raise_error(%r{Received the following error for a GET request to http://iamreallysurethatthisdoesntexist.com/canttouchthis:})
+ expect {
+ driver.visit("http://iamreallysurethatthisdoesntexist.com/canttouchthis")
+ }.to raise_error(%r{Received the following error for a GET request to http://iamreallysurethatthisdoesntexist.com/canttouchthis:})
end
end
it "should include the right host when remote" do
- @driver.visit("#{REMOTE_TEST_URL}/host")
+ driver.visit("#{REMOTE_TEST_URL}/host")
should_be_a_remote_get
end
describe '#reset!' do
- before :each do
+ before do
Capybara.default_host = 'http://www.local.com'
end
it 'should reset remote host' do
- @driver.visit("#{REMOTE_TEST_URL}/host")
+ driver.visit("#{REMOTE_TEST_URL}/host")
should_be_a_remote_get
- @driver.reset!
- @driver.visit("/host")
+ driver.reset!
+ driver.visit("/host")
should_be_a_local_get
end
end
def should_be_a_remote_get
- @driver.body.should include(REMOTE_TEST_URL)
+ driver.current_url.should include(REMOTE_TEST_URL)
end
-
+
def should_be_a_local_get
- @driver.body.should include("www.local.com")
+ driver.current_url.should include("www.local.com")
end
-
+#
end
63 spec/driver/remote_mechanize_driver_spec.rb
View
@@ -1,65 +1,46 @@
require 'spec_helper'
-describe Capybara::Mechanize::Driver do
- before(:each) do
+describe Capybara::Mechanize::Driver, 'remote' do
+ before do
Capybara.app_host = REMOTE_TEST_URL
end
-
- after(:each) do
+
+ after do
Capybara.app_host = nil
end
- before do
- @driver = Capybara::Mechanize::Driver.new
- end
-
+ let(:driver) { Capybara::Mechanize::Driver.new(ExtendedTestApp) }
+
context "in remote mode" do
- it "should not throw an error when no rack app is given" do
- running do
- Capybara::Mechanize::Driver.new
- end.should_not raise_error(ArgumentError)
- end
-
it "should pass arguments through to a get request" do
- @driver.visit("#{REMOTE_TEST_URL}/form/get", {:form => "success"})
- @driver.body.should include('success')
+ driver.visit("#{REMOTE_TEST_URL}/form/get", {:form => "success"})
+ driver.html.should include('success')
end
it "should pass arguments through to a post request" do
- @driver.post("#{REMOTE_TEST_URL}/form", {:form => "success"})
- @driver.body.should include('success')
+ driver.post("#{REMOTE_TEST_URL}/form", {:form => "success"})
+ driver.html.should include('success')
end
- context "for a post request" do
-
- it "should transform nested map in post data" do
- @driver.post("#{REMOTE_TEST_URL}/form", {:form => {:key => "value"}})
- @driver.body.should include('key: value')
+ describe "redirect" do
+ it "should handle redirects with http-params" do
+ driver.visit "#{REMOTE_TEST_URL}/redirect_with_http_param"
+ driver.html.should include('correct redirect')
end
-
end
- context "process remote request" do
-
- it "should transform nested map in post data" do
- @driver.submit(:post, "#{REMOTE_TEST_URL}/form", {:form => {:key => "value"}})
- @driver.body.should include('key: value')
+ context "for a post request" do
+ it 'transforms nested map in post data' do
+ driver.post("#{REMOTE_TEST_URL}/form", {:form => {:key => 'value'}})
+ driver.html.should include(':key=>"value"')
end
-
end
- describe "redirect" do
- it "should handle redirects with http-params" do
- @driver.visit "#{REMOTE_TEST_URL}/redirect_with_http_param"
- @driver.body.should include('correct redirect')
+ context 'process remote request' do
+ it 'transforms nested map in post data' do
+ driver.submit(:post, "#{REMOTE_TEST_URL}/form", {:form => {:key => 'value'}})
+ driver.html.should include(':key=>"value"')
end
end
-
- it_should_behave_like "driver"
- it_should_behave_like "driver with header support"
- it_should_behave_like "driver with status code support"
- it_should_behave_like "driver with cookies support"
- it_should_behave_like "driver with infinite redirect detection"
end
-
end
90 spec/session/mechanize_spec.rb
View
@@ -1,59 +1,103 @@
require 'spec_helper'
+module TestSessions
+ Mechanize = Capybara::Session.new(:mechanize, TestApp)
+end
+
+Capybara::SpecHelper.run_specs TestSessions::Mechanize, "Mechanize", :skip => [
+ :js,
+ :screenshot,
+ :frames,
+ :windows,
+ :server
+]
+
describe Capybara::Session do
context 'with mechanize driver' do
+ let(:session) { Capybara::Session.new(:mechanize, ExtendedTestApp) }
+
before do
- @session = Capybara::Session.new(:mechanize, TestApp)
- @session.driver.options[:respect_data_method] = true
Capybara.default_host = 'http://www.local.com'
end
describe '#driver' do
it "should be a mechanize driver" do
- @session.driver.should be_an_instance_of(Capybara::Mechanize::Driver)
+ session.driver.should be_an_instance_of(Capybara::Mechanize::Driver)
end
end
describe '#mode' do
it "should remember the mode" do
- @session.mode.should == :mechanize
+ session.mode.should == :mechanize
end
end
describe '#click_link' do
- it "should use data-method if available" do
- @session.visit "/with_html"
- @session.click_link "A link with data-method"
- @session.body.should include('The requested object was deleted')
+ it "should use data-method if option is true" do
+ session.driver.options[:respect_data_method] = true
+ session.visit "/with_html"
+ session.click_link "A link with data-method"
+ session.html.should include('The requested object was deleted')
+ end
+
+ it "should not use data-method if option is false" do
+ session.driver.options[:respect_data_method] = false
+ session.visit "/with_html"
+ session.click_link "A link with data-method"
+ session.html.should include('Not deleted')
+ end
+
+ it "should use data-method if available even if it's capitalized" do
+ session.driver.options[:respect_data_method] = true
+ session.visit "/with_html"
+ session.click_link "A link with capitalized data-method"
+ session.html.should include('The requested object was deleted')
+ end
+
+ after do
+ session.driver.options[:respect_data_method] = false
+ end
+ end
+
+ describe "#attach_file" do
+ context "with multipart form" do
+ it "should submit an empty form-data section if no file is submitted" do
+ session.visit("/form")
+ session.click_button("Upload Empty")
+ session.html.should include('Successfully ignored empty file field.')
+ end
end
end
it "should use the last remote url when following relative links" do
- @session.visit("#{REMOTE_TEST_URL}/relative_link_to_host")
- @session.click_link "host"
- @session.body.should include("Current host is #{REMOTE_TEST_URL}/request_info/host, method get")
+ session.visit("#{REMOTE_TEST_URL}/relative_link_to_host")
+ session.click_link "host"
+ session.body.should include("Current host is #{REMOTE_TEST_URL}/request_info/host, method get")
end
it "should use the last remote url when submitting a form with a relative action" do
- @session.visit("#{REMOTE_TEST_URL}/form_with_relative_action_to_host")
- @session.click_button "submit"
- @session.body.should include("Current host is #{REMOTE_TEST_URL}/request_info/host, method post")
+ session.visit("#{REMOTE_TEST_URL}/form_with_relative_action_to_host")
+ session.click_button "submit"
+ session.body.should include("Current host is #{REMOTE_TEST_URL}/request_info/host, method post")
end
it "should use the last url when submitting a form with no action" do
- @session.visit("#{REMOTE_TEST_URL}/request_info/form_with_no_action")
- @session.click_button "submit"
- @session.body.should include("Current host is #{REMOTE_TEST_URL}/request_info/form_with_no_action, method post")
+ session.visit("#{REMOTE_TEST_URL}/request_info/form_with_no_action")
+ session.click_button "submit"
+ session.body.should include("Current host is #{REMOTE_TEST_URL}/request_info/form_with_no_action, method post")
end
it "should send correct user agent" do
- @session.visit("#{REMOTE_TEST_URL}/request_info/user_agent")
- @session.body.should include("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.853.0 Safari/535.2")
+ session.visit("#{REMOTE_TEST_URL}/request_info/user_agent")
+ session.body.should include("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.853.0 Safari/535.2")
end
- it_should_behave_like "session"
- it_should_behave_like "session without javascript support"
- it_should_behave_like "session with headers support"
- it_should_behave_like "session with status code support"
+ context 'form referer when switching from local to remote' do
+ it 'sends the referer' do
+ session.visit "/form_posts_to/#{REMOTE_TEST_URL}/get_referer"
+ session.click_button 'submit'
+ session.body.should include 'Got referer'
+ end
+ end
end
end
106 spec/session/remote_mechanize_spec.rb
View
@@ -1,66 +1,102 @@
require 'spec_helper'
+module TestSessions
+ Mechanize = Capybara::Session.new(:mechanize, TestApp)
+end
+
+shared_context "remote tests" do
+ before do
+ Capybara.app_host = REMOTE_TEST_URL
+ end
+
+ after do
+ Capybara.app_host = nil
+ end
+end
+
+session_describe = Capybara::SpecHelper.run_specs TestSessions::Mechanize, "Mechanize", :skip => [
+ :js,
+ :screenshot,
+ :frames,
+ :windows,
+ :server
+]
+
+session_describe.include_context("remote tests")
+
+disabler = DisableExternalTests.new
+disabler.tests_to_disable = [
+ ['#visit', 'when Capybara.always_include_port is true', 'should fetch a response from the driver with an absolute url without a port'],
+ ['#reset_session!', 'raises any errors caught inside the server']
+]
+disabler.disable(session_describe)
+
describe Capybara::Session do
context 'with remote mechanize driver' do
- before(:each) do
- Capybara.app_host = REMOTE_TEST_URL
- end
+ include_context 'remote tests'
- after(:each) do
- Capybara.app_host = nil
- end
-
-
- before do
- @session = Capybara::Session.new(:mechanize)
- @session.driver.options[:respect_data_method] = true
- end
+ let(:session) { Capybara::Session.new(:mechanize, ExtendedTestApp) }
describe '#driver' do
it "should be a mechanize driver" do
- @session.driver.should be_an_instance_of(Capybara::Mechanize::Driver)
+ session.driver.should be_an_instance_of(Capybara::Mechanize::Driver)
end
end
describe '#mode' do
it "should remember the mode" do
- @session.mode.should == :mechanize
+ session.mode.should == :mechanize
end
end
describe '#click_link' do
- it "should use data-method if available" do
- @session.visit "/with_html"
- @session.click_link "A link with data-method"
- @session.body.should include('The requested object was deleted')
+ it "should use data-method if option is true" do
+ session.driver.options[:respect_data_method] = true
+ session.visit "/with_html"
+ session.click_link "A link with data-method"
+ session.html.should include('The requested object was deleted')
end
- end
-
+ it "should not use data-method if option is false" do
+ session.driver.options[:respect_data_method] = false
+ session.visit "/with_html"
+ session.click_link "A link with data-method"
+ session.html.should include('Not deleted')
+ end
- # Pending: Still 16 failing tests here (result is 706 examples, 16 failures, instead of 385 examples)
- # it_should_behave_like "session"
-
- it_should_behave_like "session without javascript support"
- it_should_behave_like "session with headers support"
- it_should_behave_like "session with status code support"
+ it "should use data-method if available even if it's capitalized" do
+ session.driver.options[:respect_data_method] = true
+ session.visit "/with_html"
+ session.click_link "A link with capitalized data-method"
+ session.html.should include('The requested object was deleted')
+ end
+ after do
+ session.driver.options[:respect_data_method] = false
+ end
+ end
- context "remote app in a sub-path" do
- before :each do
- Capybara.app_host = REMOTE_TEST_URL
+ describe "#attach_file" do
+ context "with multipart form" do
+ it "should submit an empty form-data section if no file is submitted" do
+ session.visit("/form")
+ session.click_button("Upload Empty")
+ session.html.should include('Successfully ignored empty file field.')
+ end
end
+ end
+ context "remote app in a sub-path" do
it "follows relative link correctly" do
- @session.visit "/subsite/relative_link_to_host"
- @session.click_link "host"
- @session.body.should include('request_info2/host')
+ session.visit "/subsite/relative_link_to_host"
+ session.click_link "host"
+ session.body.should include('request_info2/host')
end
it "follows local link correctly" do
- @session.visit "/subsite/local_link_to_host"
- @session.click_link "host"
- @session.body.should include('request_info2/host')
+ session.visit "/subsite/local_link_to_host"
+ session.click_link "host"
+ session.body.should include('request_info2/host')
end
end
end
45 spec/spec_helper.rb
View
@@ -1,22 +1,12 @@
-require 'bundler/setup'
-require 'capybara'
-require 'capybara/dsl'
+require 'capybara/spec/spec_helper'
require 'capybara/mechanize'
require 'capybara/spec/extended_test_app'
-require 'sinatra'
+PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..')).freeze
-# TODO move this stuff into capybara
-require 'capybara/spec/driver'
-require 'capybara/spec/session'
+$LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
-alias :running :lambda
-
-Capybara.default_wait_time = 0 # less timeout so tests run faster
-Capybara.app = ExtendedTestApp
-
-rack_server = Capybara::Server.new(Capybara.app)
-rack_server.boot
+Dir[File.join(PROJECT_ROOT, 'spec', 'support', '**', '*.rb')].each { |file| require(file) }
RSpec.configure do |config|
# Spruce up the focus!
@@ -24,28 +14,15 @@
config.run_all_when_everything_filtered = true
config.treat_symbols_as_metadata_keys_with_true_values = true
+ # Used with DisableExternalTests
+ config.filter_run_excluding :external_test_disabled
+
config.after do
- Capybara.default_selector = :xpath
Capybara::Mechanize.local_hosts = nil
end
-end
-
-REMOTE_TEST_URL = "http://localhost:#{rack_server.port}"
-
-
-# for testing private methods, courtesy of
-# http://kailuowang.blogspot.com.au/2010/08/testing-private-methods-in-rspec.html
-def describe_internally *args, &block
- example = describe *args, &block
- klass = args[0]
- if klass.is_a? Class
- saved_private_instance_methods = klass.private_instance_methods
- example.before do
- klass.class_eval { public *saved_private_instance_methods }
- end
- example.after do
- klass.class_eval { private *saved_private_instance_methods }
- end
- end
+ Capybara::SpecHelper.configure(config)
end
+
+setup = ExtendedTestAppSetup.new.boot
+REMOTE_TEST_URL = setup.remote_test_url
20 spec/support/disable_external_tests.rb
View
@@ -0,0 +1,20 @@
+class DisableExternalTests
+ attr_accessor :tests_to_disable
+
+ def disable(top_level_example_group)
+ tests_to_disable.each do |to_disable|
+ example_group = top_level_example_group
+
+ example_description = to_disable.pop
+
+ to_disable.each do |description|
+ example_group = example_group.children.find{ |g| g.description == description }
+ end
+
+ example = example_group.examples.find{ |e| e.description == example_description }
+
+ example.metadata[:external_test_disabled] = true
+ end
+
+ end
+end
30 spec/support/extended_test_app_setup.rb
View
@@ -0,0 +1,30 @@
+# This class works around some weirdness with Capybara's test suite and sinatra's behavior.
+# We need to make sure that sinatra uses TestApp for at least one request before the Capybara session
+# specs run. Without this we get errors from sinatra trying to handle requests with TestApp.clone
+class ExtendedTestAppSetup
+ include Capybara::DSL
+
+ attr_reader :remote_test_url
+
+ def boot
+ boot_test_app
+ boot_remote_app
+
+ self
+ end
+
+ def boot_test_app
+ Capybara.app = TestApp
+ dummy_server = Capybara::Server.new(TestApp)
+ dummy_server.boot
+
+ # Boot TestApp's Sinatra
+ visit '/'
+ end
+
+ def boot_remote_app
+ remote_server = Capybara::Server.new(ExtendedTestApp)
+ remote_server.boot
+ @remote_test_url = "http://localhost:#{remote_server.port}"
+ end
+end
Something went wrong with that request. Please try again.