ryansch-capybara-mechanize 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.mdown ADDED
@@ -0,0 +1,68 @@
1
+ Capybara-mechanize
2
+ ==================
3
+
4
+ This gems makes it possible to use Capybara for (partially) remote testing. It inherits most functionality from the RackTest driver and only uses [Mechanize](http://github.com/tenderlove/mechanize) for remote requests.
5
+
6
+ It is currently in use to test the integration between a Rails application and Twitter authorization and sharing.
7
+
8
+ This gem is a [Capybara](http://github.com/jnicklas/capybara) extension. I have been inspired by the Capybara driver and some earlier efforts for a Mechanize driver.
9
+
10
+ Thanks to [Pinkelstar](http://www.pinkelstar.com) for giving me the time and the need to develop this gem.
11
+
12
+ ### Installation
13
+
14
+ gem install capybara-mechanize
15
+
16
+ ### Usage without Cucumber
17
+
18
+ require 'capybara/mechanize'
19
+
20
+ ### Usage with Cucumber and tags
21
+
22
+ A @mechanize tag is added to your hooks when you add the following line to your env.rb
23
+
24
+ require 'capybara/mechanize/cucumber'
25
+
26
+ The following scenario will then be using the Mechanize driver
27
+
28
+ @mechanize
29
+ Scenario: do something remote
30
+ When I click the remote link
31
+
32
+ ### Remote testing
33
+
34
+ When you want to use this driver to test a remote application. You have to set the app_host:
35
+
36
+ Capybara.app_host = "http://www.yourapp.com"
37
+
38
+ Note that I haven't tested this case for my self yet. The Capybara tests pass for this situation though so it should work! Please provide me with feedback if it doesn't.
39
+
40
+ ## Running tests
41
+
42
+ Run bundler
43
+
44
+ bundle install
45
+
46
+ Then you are ready to run the test like so
47
+
48
+ bundle exec rake spec
49
+
50
+ Todo
51
+ ----
52
+ * Make the last 12 failing remote session spec pass, see remote_mechanize_spec and uncomment one line there to see them fail
53
+ * Test this driver with non-rack/non-ruby projects
54
+
55
+ Note on Patches/Pull Requests
56
+ -----------------------------
57
+
58
+ * Fork the project.
59
+ * Make your feature addition or bug fix.
60
+ * Add tests for it. This is important so I don't break it in a
61
+ future version unintentionally.
62
+ * Commit, do not mess with rakefile, version, or history.
63
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
64
+ * Send me a pull request. Bonus points for topic branches.
65
+
66
+ Copyright
67
+ ---------
68
+ Copyright (c) 2010-2012 Jeroen van Dijk. See LICENSE for details.
@@ -0,0 +1,24 @@
1
+ require 'capybara'
2
+
3
+ module Capybara::Mechanize
4
+ class << self
5
+
6
+ # Host that should be considered local (includes default_host)
7
+ def local_hosts
8
+ @local_hosts ||= begin
9
+ default_host = URI.parse(Capybara.default_host || "").host || Capybara.default_host
10
+ [default_host].compact
11
+ end
12
+ end
13
+
14
+ def local_hosts=(hosts)
15
+ @local_hosts = hosts
16
+ end
17
+ end
18
+ end
19
+
20
+ require 'capybara/mechanize/driver'
21
+
22
+ Capybara.register_driver :mechanize do |app|
23
+ Capybara::Mechanize::Driver.new(app)
24
+ end
@@ -0,0 +1,172 @@
1
+ require 'capybara/rack_test/driver'
2
+ require 'mechanize'
3
+ require 'capybara/mechanize/node'
4
+ require 'capybara/mechanize/form'
5
+
6
+ class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
7
+ extend Forwardable
8
+
9
+ def_delegator :agent, :scheme_handlers
10
+ def_delegator :agent, :scheme_handlers=
11
+
12
+ def initialize(driver)
13
+ @agent = ::Mechanize.new
14
+ @agent.redirect_ok = false
15
+ @agent.user_agent = default_user_agent
16
+ super
17
+ end
18
+
19
+ def reset_host!
20
+ @last_remote_uri = nil
21
+ @last_request_remote = nil
22
+ super
23
+ end
24
+
25
+ def current_url
26
+ last_request_remote? ? remote_response.current_url : super
27
+ end
28
+
29
+ def last_response
30
+ last_request_remote? ? remote_response : super
31
+ end
32
+
33
+ # For each of these http methods, we want to intercept the method call.
34
+ # Then we determine if the call is remote or local.
35
+ # Remote: Handle it with our process_remote_request method.
36
+ # Local: Register the local request and call super to let RackTest get it.
37
+ [:get, :post, :put, :delete].each do |method|
38
+ define_method(method) do |path, params = {}, env = {}, &block|
39
+ path = @last_path if path.nil? || path.empty?
40
+
41
+ if remote?(path)
42
+ process_remote_request(method, path, params, env, &block)
43
+ else
44
+ register_local_request
45
+ super(path, params, env, &block)
46
+ end
47
+
48
+ @last_path = path
49
+ end
50
+ end
51
+
52
+ def remote?(url)
53
+ if Capybara.app_host
54
+ true
55
+ else
56
+ host = URI.parse(url).host
57
+
58
+ if host.nil?
59
+ last_request_remote?
60
+ else
61
+ !Capybara::Mechanize.local_hosts.include?(host)
62
+ end
63
+ end
64
+ end
65
+
66
+ def find(selector)
67
+ dom.xpath(selector).map { |node| Capybara::Mechanize::Node.new(self, node) }
68
+ end
69
+
70
+ attr_reader :agent
71
+
72
+ private
73
+
74
+ def last_request_remote?
75
+ !!@last_request_remote
76
+ end
77
+
78
+ def register_local_request
79
+ @last_remote_uri = nil
80
+ @last_request_remote = false
81
+ end
82
+
83
+ def remote_request_path
84
+ @last_remote_uri.nil? ? nil : @last_remote_uri.path
85
+ end
86
+
87
+ def request_path
88
+ last_request_remote? ? remote_request_path : super
89
+ end
90
+
91
+ def process_remote_request(method, url, attributes, headers)
92
+ if remote?(url)
93
+ uri = URI.parse(url)
94
+ @last_remote_uri = uri
95
+ url = uri.to_s
96
+
97
+ reset_cache!
98
+ begin
99
+ if method == :post
100
+ if attributes.is_a? Mechanize::Form
101
+ submit_mechanize_form(url, attributes, headers)
102
+ else
103
+ @agent.send(method, url, attributes, headers)
104
+ end
105
+ elsif method == :get
106
+ if attributes.is_a? Mechanize::Form
107
+ submit_mechanize_form(url, attributes, headers)
108
+ else
109
+ referer = headers['HTTP_REFERER']
110
+ @agent.send(method, url, attributes, referer, headers)
111
+ end
112
+ else
113
+ @agent.send(method, url, attributes, headers)
114
+ end
115
+ rescue => e
116
+ raise "Received the following error for a #{method.to_s.upcase} request to #{url}: '#{e.message}'"
117
+ end
118
+ @last_request_remote = true
119
+ end
120
+ end
121
+
122
+ def submit_mechanize_form(url, form, headers)
123
+ form.action = url
124
+ @agent.submit(form, nil, headers)
125
+ end
126
+
127
+ def remote_response
128
+ ResponseProxy.new(@agent.current_page) if @agent.current_page
129
+ end
130
+
131
+ def default_user_agent
132
+ "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"
133
+ end
134
+
135
+ class ResponseProxy
136
+ extend Forwardable
137
+
138
+ def_delegator :page, :body
139
+
140
+ attr_reader :page
141
+
142
+ def initialize(page)
143
+ @page = page
144
+ end
145
+
146
+ def current_url
147
+ page.uri.to_s
148
+ end
149
+
150
+ def headers
151
+ # Hax the content-type contains utf8, so Capybara specs are failing, need to ask mailinglist
152
+ headers = page.response
153
+ headers["content-type"].gsub!(';charset=utf-8', '') if headers["content-type"]
154
+ headers
155
+ end
156
+
157
+ def [](key)
158
+ headers[key]
159
+ end
160
+
161
+ def status
162
+ page.code.to_i
163
+ end
164
+
165
+ def redirect?
166
+ status >= 300 && status < 400
167
+ end
168
+
169
+ end
170
+
171
+ end
172
+
@@ -0,0 +1,5 @@
1
+ require 'capybara/mechanize'
2
+
3
+ Before('@mechanize') do
4
+ Capybara.current_driver = :mechanize
5
+ end
@@ -0,0 +1,19 @@
1
+ require 'capybara/mechanize/browser'
2
+
3
+ class Capybara::Mechanize::Driver < Capybara::RackTest::Driver
4
+
5
+ def initialize(app, options = {})
6
+ raise ArgumentError, "mechanize requires a rack application, but none was given" unless app
7
+
8
+ super
9
+ end
10
+
11
+ def remote?(url)
12
+ browser.remote?(url)
13
+ end
14
+
15
+ def browser
16
+ @browser ||= Capybara::Mechanize::Browser.new(self)
17
+ end
18
+
19
+ end
@@ -0,0 +1,65 @@
1
+ class Capybara::Mechanize::Form < Capybara::RackTest::Form
2
+
3
+ def params(button)
4
+ if !use_mechanize?
5
+ return super
6
+ end
7
+
8
+ node = {}
9
+ # Create a fake form
10
+ class << node
11
+ def search(*args); []; end
12
+ end
13
+ node['method'] = method.to_s.upcase
14
+
15
+ if self.multipart?
16
+ node['enctype'] = 'multipart/form-data'
17
+ else
18
+ node['enctype'] = 'application/x-www-form-urlencoded'
19
+ end
20
+
21
+ @m_form = Mechanize::Form.new(node, nil, form_referer)
22
+
23
+ super
24
+
25
+ @m_form
26
+ end
27
+
28
+ private
29
+
30
+ def merge_param!(params, key, value)
31
+ if !use_mechanize?
32
+ return super
33
+ end
34
+
35
+ if value.is_a? NilUploadedFile
36
+ # Adding a nil value here will result in the form element existing with the empty string as its value.
37
+ # Instead don't add the form element at all.
38
+ return params
39
+ end
40
+
41
+ if value.is_a? Rack::Test::UploadedFile
42
+ @m_form.enctype = 'multipart/form-data'
43
+
44
+ ul = Mechanize::Form::FileUpload.new({'name' => key.to_s}, value.original_filename)
45
+ ul.mime_type = value.content_type
46
+ ul.file_data = (value.rewind; value.read)
47
+
48
+ @m_form.file_uploads << ul
49
+
50
+ return params
51
+ end
52
+
53
+ @m_form.fields << Mechanize::Form::Field.new({'name' => key.to_s}, value)
54
+
55
+ params
56
+ end
57
+
58
+ def use_mechanize?
59
+ driver.remote?(native['action'].to_s)
60
+ end
61
+
62
+ def form_referer
63
+ driver.last_response.page
64
+ end
65
+ end
@@ -0,0 +1,10 @@
1
+ class Capybara::Mechanize::Node < Capybara::RackTest::Node
2
+ def click
3
+ if tag_name == 'a'
4
+ super
5
+ elsif (tag_name == 'input' and %w(submit image).include?(type)) or
6
+ ((tag_name == 'button') and type.nil? or type == "submit")
7
+ Capybara::Mechanize::Form.new(driver, form).submit(self)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module Capybara
2
+ module Mechanize
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
@@ -0,0 +1,65 @@
1
+ require 'capybara/spec/test_app'
2
+
3
+ class ExtendedTestApp < TestApp#< Sinatra::Base
4
+ set :environment, :production # so we don't get debug info that makes our test pass!
5
+ disable :protection
6
+
7
+ get %r{/redirect_to/(.*)} do
8
+ redirect params[:captures].first
9
+ end
10
+
11
+ get '/form_with_relative_action_to_host' do
12
+ %{<form action="/request_info/host" method="post">
13
+ <input type="submit" value="submit" />
14
+ </form>}
15
+ end
16
+
17
+ get '/request_info/form_with_no_action' do
18
+ %{<form method="post">
19
+ <input type="submit" value="submit" />
20
+ </form>}
21
+ end
22
+
23
+ get '/relative_link_to_host' do
24
+ %{<a href="/request_info/host">host</a>}
25
+ end
26
+
27
+ get '/request_info/user_agent' do
28
+ request.user_agent
29
+ end
30
+
31
+ get '/request_info/*' do
32
+ current_request_info
33
+ end
34
+
35
+ post '/request_info/*' do
36
+ current_request_info
37
+ end
38
+
39
+ get '/subsite/relative_link_to_host' do
40
+ %{<a href="/subsite/request_info2/host">host</a>}
41
+ end
42
+
43
+ get '/subsite/local_link_to_host' do
44
+ %{<a href="request_info2/host">host</a>}
45
+ end
46
+
47
+ get '/subsite/request_info2/*' do
48
+ "subsite: " + current_request_info
49
+ end
50
+
51
+ get '/redirect_with_http_param' do
52
+ redirect '/redirect_target?foo=http'
53
+ end
54
+
55
+ get '/redirect_target' do
56
+ %{correct redirect}
57
+ end
58
+
59
+ private
60
+
61
+ def current_request_info
62
+ "Current host is #{request.url}, method #{request.request_method.downcase}"
63
+ end
64
+ end
65
+
@@ -0,0 +1,215 @@
1
+ require 'spec_helper'
2
+
3
+ describe Capybara::Mechanize::Driver, 'local' do
4
+ let(:driver) { Capybara::Mechanize::Driver.new(ExtendedTestApp) }
5
+
6
+ describe ':headers option' do
7
+ it 'should always set headers' do
8
+ driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'})
9
+ driver.visit('/get_header')
10
+ driver.html.should include('foobar')
11
+ end
12
+
13
+ it 'should keep headers on link clicks' do
14
+ driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'})
15
+ driver.visit('/header_links')
16
+ driver.find('.//a').first.click
17
+ driver.html.should include('foobar')
18
+ end
19
+
20
+ it 'should keep headers on form submit' do
21
+ driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'})
22
+ driver.visit('/header_links')
23
+ driver.find('.//input').first.click
24
+ driver.html.should include('foobar')
25
+ end
26
+
27
+ it 'should keep headers on redirects' do
28
+ driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'})
29
+ driver.visit('/get_header_via_redirect')
30
+ driver.html.should include('foobar')
31
+ end
32
+ end
33
+
34
+ describe ':follow_redirects option' do
35
+ it "defaults to following redirects" do
36
+ driver = Capybara::RackTest::Driver.new(TestApp)
37
+
38
+ driver.visit('/redirect')
39
+ driver.response.header['Location'].should be_nil
40
+ driver.browser.current_url.should match %r{/landed$}
41
+ end
42
+
43
+ it "is possible to not follow redirects" do
44
+ driver = Capybara::RackTest::Driver.new(TestApp, :follow_redirects => false)
45
+
46
+ driver.visit('/redirect')
47
+ driver.response.header['Location'].should match %r{/redirect_again$}
48
+ driver.browser.current_url.should match %r{/redirect$}
49
+ end
50
+ end
51
+
52
+ describe ':redirect_limit option' do
53
+ context "with default redirect limit" do
54
+ let(:driver) { Capybara::RackTest::Driver.new(TestApp) }
55
+
56
+ it "should follow 5 redirects" do
57
+ driver.visit("/redirect/5/times")
58
+ driver.html.should include('redirection complete')
59
+ end
60
+
61
+ it "should not follow more than 6 redirects" do
62
+ expect do
63
+ driver.visit("/redirect/6/times")
64
+ end.to raise_error(Capybara::InfiniteRedirectError)
65
+ end
66
+ end
67
+
68
+ context "with 21 redirect limit" do
69
+ let(:driver) { Capybara::RackTest::Driver.new(TestApp, :redirect_limit => 21) }
70
+
71
+ it "should follow 21 redirects" do
72
+ driver.visit("/redirect/21/times")
73
+ driver.html.should include('redirection complete')
74
+ end
75
+
76
+ it "should not follow more than 21 redirects" do
77
+ expect do
78
+ driver.visit("/redirect/22/times")
79
+ end.to raise_error(Capybara::InfiniteRedirectError)
80
+ end
81
+ end
82
+ end
83
+
84
+ it "should default to local mode for relative paths" do
85
+ driver.should_not be_remote('/')
86
+ end
87
+
88
+ it "should default to local mode for the default host" do
89
+ driver.should_not be_remote('http://www.example.com')
90
+ end
91
+
92
+ context "with an app_host" do
93
+
94
+ before do
95
+ Capybara.app_host = 'http://www.remote.com'
96
+ end
97
+
98
+ after do
99
+ Capybara.app_host = nil
100
+ end
101
+
102
+ it "should treat urls as remote" do
103
+ driver.should be_remote('http://www.remote.com')
104
+ end
105
+ end
106
+
107
+ context "with a default url, no app host" do
108
+ before do
109
+ Capybara.default_host = 'www.local.com'
110
+ end
111
+
112
+ it "should allow local hosts to be set" do
113
+ Capybara::Mechanize.local_hosts = ['subdomain.local.com']
114
+ driver.should_not be_remote('http://subdomain.local.com')
115
+ end
116
+
117
+ it "should treat urls with the same host names as local" do
118
+ driver.should_not be_remote('http://www.local.com')
119
+ end
120
+
121
+ it "should treat other urls as remote" do
122
+ driver.should be_remote('http://www.remote.com')
123
+ end
124
+
125
+ it "should treat relative paths as remote if the previous request was remote" do
126
+ driver.visit(REMOTE_TEST_URL)
127
+ driver.should be_remote('/some_relative_link')
128
+ end
129
+
130
+ it "should treat relative paths as local if the previous request was local" do
131
+ driver.visit('http://www.local.com')
132
+ driver.should_not be_remote('/some_relative_link')
133
+ end
134
+
135
+ it "should receive the right host" do
136
+ driver.visit('http://www.local.com/host')
137
+ should_be_a_local_get
138
+ end
139
+
140
+ it "should consider relative paths to be local when the previous request was local" do
141
+ driver.visit('http://www.local.com/host')
142
+ driver.visit('/host')
143
+
144
+ should_be_a_local_get
145
+ driver.should_not be_remote('/first_local')
146
+ end
147
+
148
+ it "should consider relative paths to be remote when the previous request was remote" do
149
+ driver.visit("#{REMOTE_TEST_URL}/host")
150
+ driver.get('/host')
151
+
152
+ should_be_a_remote_get
153
+ driver.should be_remote('/second_remote')
154
+ end
155
+
156
+ it "should always switch to the right context" do
157
+ driver.visit('http://www.local.com/host')
158
+ driver.get('/host')
159
+ driver.get("#{REMOTE_TEST_URL}/host")
160
+ driver.get('/host')
161
+ driver.get('http://www.local.com/host')
162
+
163
+ should_be_a_local_get
164
+ driver.should_not be_remote('/second_local')
165
+ end
166
+
167
+ it "should follow redirects from local to remote" do
168
+ driver.visit("http://www.local.com/redirect_to/#{REMOTE_TEST_URL}/host")
169
+ should_be_a_remote_get
170
+ end
171
+
172
+ it "should follow redirects from remote to local" do
173
+ driver.visit("#{REMOTE_TEST_URL}/redirect_to/http://www.local.com/host")
174
+ should_be_a_local_get
175
+ end
176
+
177
+ after do
178
+ Capybara.default_host = nil
179
+ end
180
+
181
+ it "should raise a useful error for sites that return a 404, because it is probably a misconfiguration" do
182
+ expect {
183
+ driver.visit("http://iamreallysurethatthisdoesntexist.com/canttouchthis")
184
+ }.to raise_error(%r{Received the following error for a GET request to http://iamreallysurethatthisdoesntexist.com/canttouchthis:})
185
+ end
186
+ end
187
+
188
+ it "should include the right host when remote" do
189
+ driver.visit("#{REMOTE_TEST_URL}/host")
190
+ should_be_a_remote_get
191
+ end
192
+
193
+ describe '#reset!' do
194
+ before do
195
+ Capybara.default_host = 'http://www.local.com'
196
+ end
197
+
198
+ it 'should reset remote host' do
199
+ driver.visit("#{REMOTE_TEST_URL}/host")
200
+ should_be_a_remote_get
201
+ driver.reset!
202
+ driver.visit("/host")
203
+ should_be_a_local_get
204
+ end
205
+ end
206
+
207
+ def should_be_a_remote_get
208
+ driver.current_url.should include(REMOTE_TEST_URL)
209
+ end
210
+
211
+ def should_be_a_local_get
212
+ driver.current_url.should include("www.local.com")
213
+ end
214
+ #
215
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Capybara::Mechanize::Driver, 'remote' do
4
+ before do
5
+ Capybara.app_host = REMOTE_TEST_URL
6
+ end
7
+
8
+ after do
9
+ Capybara.app_host = nil
10
+ end
11
+
12
+ let(:driver) { Capybara::Mechanize::Driver.new(ExtendedTestApp) }
13
+
14
+ context "in remote mode" do
15
+ it "should pass arguments through to a get request" do
16
+ driver.visit("#{REMOTE_TEST_URL}/form/get", {:form => "success"})
17
+ driver.html.should include('success')
18
+ end
19
+
20
+ it "should pass arguments through to a post request" do
21
+ driver.post("#{REMOTE_TEST_URL}/form", {:form => "success"})
22
+ driver.html.should include('success')
23
+ end
24
+
25
+ describe "redirect" do
26
+ it "should handle redirects with http-params" do
27
+ driver.visit "#{REMOTE_TEST_URL}/redirect_with_http_param"
28
+ driver.html.should include('correct redirect')
29
+ end
30
+ end
31
+
32
+ context "for a post request" do
33
+ it 'transforms nested map in post data' do
34
+ driver.post("#{REMOTE_TEST_URL}/form", {:form => {:key => 'value'}})
35
+ driver.html.should include(':key=>"value"')
36
+ end
37
+ end
38
+
39
+ context 'process remote request' do
40
+ it 'transforms nested map in post data' do
41
+ driver.submit(:post, "#{REMOTE_TEST_URL}/form", {:form => {:key => 'value'}})
42
+ driver.html.should include(':key=>"value"')
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ module TestSessions
4
+ Mechanize = Capybara::Session.new(:mechanize, TestApp)
5
+ end
6
+
7
+ Capybara::SpecHelper.run_specs TestSessions::Mechanize, "Mechanize", :skip => [
8
+ :js,
9
+ :screenshot,
10
+ :frames,
11
+ :windows,
12
+ :server
13
+ ]
14
+
15
+ describe Capybara::Session do
16
+ context 'with mechanize driver' do
17
+ let(:session) { Capybara::Session.new(:mechanize, ExtendedTestApp) }
18
+
19
+ before do
20
+ Capybara.default_host = 'http://www.local.com'
21
+ end
22
+
23
+ describe '#driver' do
24
+ it "should be a mechanize driver" do
25
+ session.driver.should be_an_instance_of(Capybara::Mechanize::Driver)
26
+ end
27
+ end
28
+
29
+ describe '#mode' do
30
+ it "should remember the mode" do
31
+ session.mode.should == :mechanize
32
+ end
33
+ end
34
+
35
+ describe '#click_link' do
36
+ it "should use data-method if option is true" do
37
+ session.driver.options[:respect_data_method] = true
38
+ session.visit "/with_html"
39
+ session.click_link "A link with data-method"
40
+ session.html.should include('The requested object was deleted')
41
+ end
42
+
43
+ it "should not use data-method if option is false" do
44
+ session.driver.options[:respect_data_method] = false
45
+ session.visit "/with_html"
46
+ session.click_link "A link with data-method"
47
+ session.html.should include('Not deleted')
48
+ end
49
+
50
+ it "should use data-method if available even if it's capitalized" do
51
+ session.driver.options[:respect_data_method] = true
52
+ session.visit "/with_html"
53
+ session.click_link "A link with capitalized data-method"
54
+ session.html.should include('The requested object was deleted')
55
+ end
56
+
57
+ after do
58
+ session.driver.options[:respect_data_method] = false
59
+ end
60
+ end
61
+
62
+ describe "#attach_file" do
63
+ context "with multipart form" do
64
+ it "should submit an empty form-data section if no file is submitted" do
65
+ session.visit("/form")
66
+ session.click_button("Upload Empty")
67
+ session.html.should include('Successfully ignored empty file field.')
68
+ end
69
+ end
70
+ end
71
+
72
+ it "should use the last remote url when following relative links" do
73
+ session.visit("#{REMOTE_TEST_URL}/relative_link_to_host")
74
+ session.click_link "host"
75
+ session.body.should include("Current host is #{REMOTE_TEST_URL}/request_info/host, method get")
76
+ end
77
+
78
+ it "should use the last remote url when submitting a form with a relative action" do
79
+ session.visit("#{REMOTE_TEST_URL}/form_with_relative_action_to_host")
80
+ session.click_button "submit"
81
+ session.body.should include("Current host is #{REMOTE_TEST_URL}/request_info/host, method post")
82
+ end
83
+
84
+ it "should use the last url when submitting a form with no action" do
85
+ session.visit("#{REMOTE_TEST_URL}/request_info/form_with_no_action")
86
+ session.click_button "submit"
87
+ session.body.should include("Current host is #{REMOTE_TEST_URL}/request_info/form_with_no_action, method post")
88
+ end
89
+
90
+ it "should send correct user agent" do
91
+ session.visit("#{REMOTE_TEST_URL}/request_info/user_agent")
92
+ 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")
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ module TestSessions
4
+ Mechanize = Capybara::Session.new(:mechanize, TestApp)
5
+ end
6
+
7
+ shared_context "remote tests" do
8
+ before do
9
+ Capybara.app_host = REMOTE_TEST_URL
10
+ end
11
+
12
+ after do
13
+ Capybara.app_host = nil
14
+ end
15
+ end
16
+
17
+ session_describe = Capybara::SpecHelper.run_specs TestSessions::Mechanize, "Mechanize", :skip => [
18
+ :js,
19
+ :screenshot,
20
+ :frames,
21
+ :windows,
22
+ :server
23
+ ]
24
+
25
+ session_describe.include_context("remote tests")
26
+
27
+ disabler = DisableExternalTests.new
28
+ disabler.tests_to_disable = [
29
+ ['#visit', 'when Capybara.always_include_port is true', 'should fetch a response from the driver with an absolute url without a port'],
30
+ ['#reset_session!', 'raises any errors caught inside the server']
31
+ ]
32
+ disabler.disable(session_describe)
33
+
34
+ describe Capybara::Session do
35
+ context 'with remote mechanize driver' do
36
+ include_context 'remote tests'
37
+
38
+ let(:session) { Capybara::Session.new(:mechanize, ExtendedTestApp) }
39
+
40
+ describe '#driver' do
41
+ it "should be a mechanize driver" do
42
+ session.driver.should be_an_instance_of(Capybara::Mechanize::Driver)
43
+ end
44
+ end
45
+
46
+ describe '#mode' do
47
+ it "should remember the mode" do
48
+ session.mode.should == :mechanize
49
+ end
50
+ end
51
+
52
+ describe '#click_link' do
53
+ it "should use data-method if option is true" do
54
+ session.driver.options[:respect_data_method] = true
55
+ session.visit "/with_html"
56
+ session.click_link "A link with data-method"
57
+ session.html.should include('The requested object was deleted')
58
+ end
59
+
60
+ it "should not use data-method if option is false" do
61
+ session.driver.options[:respect_data_method] = false
62
+ session.visit "/with_html"
63
+ session.click_link "A link with data-method"
64
+ session.html.should include('Not deleted')
65
+ end
66
+
67
+ it "should use data-method if available even if it's capitalized" do
68
+ session.driver.options[:respect_data_method] = true
69
+ session.visit "/with_html"
70
+ session.click_link "A link with capitalized data-method"
71
+ session.html.should include('The requested object was deleted')
72
+ end
73
+
74
+ after do
75
+ session.driver.options[:respect_data_method] = false
76
+ end
77
+ end
78
+
79
+ describe "#attach_file" do
80
+ context "with multipart form" do
81
+ it "should submit an empty form-data section if no file is submitted" do
82
+ session.visit("/form")
83
+ session.click_button("Upload Empty")
84
+ session.html.should include('Successfully ignored empty file field.')
85
+ end
86
+ end
87
+ end
88
+
89
+ context "remote app in a sub-path" do
90
+ it "follows relative link correctly" do
91
+ session.visit "/subsite/relative_link_to_host"
92
+ session.click_link "host"
93
+ session.body.should include('request_info2/host')
94
+ end
95
+
96
+ it "follows local link correctly" do
97
+ session.visit "/subsite/local_link_to_host"
98
+ session.click_link "host"
99
+ session.body.should include('request_info2/host')
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,28 @@
1
+ require 'capybara/spec/spec_helper'
2
+ require 'capybara/mechanize'
3
+ require 'capybara/spec/extended_test_app'
4
+
5
+ PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..')).freeze
6
+
7
+ $LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
8
+
9
+ Dir[File.join(PROJECT_ROOT, 'spec', 'support', '**', '*.rb')].each { |file| require(file) }
10
+
11
+ RSpec.configure do |config|
12
+ # Spruce up the focus!
13
+ config.filter_run :focus => true
14
+ config.run_all_when_everything_filtered = true
15
+ config.treat_symbols_as_metadata_keys_with_true_values = true
16
+
17
+ # Used with DisableExternalTests
18
+ config.filter_run_excluding :external_test_disabled
19
+
20
+ config.after do
21
+ Capybara::Mechanize.local_hosts = nil
22
+ end
23
+
24
+ Capybara::SpecHelper.configure(config)
25
+ end
26
+
27
+ setup = ExtendedTestAppSetup.new.boot
28
+ REMOTE_TEST_URL = setup.remote_test_url
@@ -0,0 +1,20 @@
1
+ class DisableExternalTests
2
+ attr_accessor :tests_to_disable
3
+
4
+ def disable(top_level_example_group)
5
+ tests_to_disable.each do |to_disable|
6
+ example_group = top_level_example_group
7
+
8
+ example_description = to_disable.pop
9
+
10
+ to_disable.each do |description|
11
+ example_group = example_group.children.select{ |g| g.description == description }.first
12
+ end
13
+
14
+ example = example_group.examples.select{ |e| e.description == example_description }.first
15
+
16
+ example.metadata[:external_test_disabled] = true
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,30 @@
1
+ # This class works around some weirdness with Capybara's test suite and sinatra's behavior.
2
+ # We need to make sure that sinatra uses TestApp for at least one request before the Capybara session
3
+ # specs run. Without this we get errors from sinatra trying to handle requests with TestApp.clone
4
+ class ExtendedTestAppSetup
5
+ include Capybara::DSL
6
+
7
+ attr_reader :remote_test_url
8
+
9
+ def boot
10
+ boot_test_app
11
+ boot_remote_app
12
+
13
+ self
14
+ end
15
+
16
+ def boot_test_app
17
+ Capybara.app = TestApp
18
+ dummy_server = Capybara::Server.new(TestApp)
19
+ dummy_server.boot
20
+
21
+ # Boot TestApp's Sinatra
22
+ visit '/'
23
+ end
24
+
25
+ def boot_remote_app
26
+ remote_server = Capybara::Server.new(ExtendedTestApp)
27
+ remote_server.boot
28
+ @remote_test_url = "http://localhost:#{remote_server.port}"
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ryansch-capybara-mechanize
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jeroen van Dijk
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mechanize
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.5'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.5'
30
+ - !ruby/object:Gem::Dependency
31
+ name: capybara
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '2.0'
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.1
41
+ type: :runtime
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: '2.0'
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: 2.0.1
52
+ description: RackTest driver for Capybara, but with remote request support thanks
53
+ to mechanize
54
+ email: jeroen@jeevidee.nl
55
+ executables: []
56
+ extensions: []
57
+ extra_rdoc_files: []
58
+ files:
59
+ - lib/capybara/mechanize/browser.rb
60
+ - lib/capybara/mechanize/cucumber.rb
61
+ - lib/capybara/mechanize/driver.rb
62
+ - lib/capybara/mechanize/form.rb
63
+ - lib/capybara/mechanize/node.rb
64
+ - lib/capybara/mechanize/version.rb
65
+ - lib/capybara/mechanize.rb
66
+ - lib/capybara/spec/extended_test_app.rb
67
+ - spec/driver/mechanize_driver_spec.rb
68
+ - spec/driver/remote_mechanize_driver_spec.rb
69
+ - spec/session/mechanize_spec.rb
70
+ - spec/session/remote_mechanize_spec.rb
71
+ - spec/spec_helper.rb
72
+ - spec/support/disable_external_tests.rb
73
+ - spec/support/extended_test_app_setup.rb
74
+ - README.mdown
75
+ homepage: https://github.com/ryansch/capybara-mechanize
76
+ licenses: []
77
+ post_install_message:
78
+ rdoc_options:
79
+ - --charset=UTF-8
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ segments:
89
+ - 0
90
+ hash: 728688646484683167
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 1.8.24
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: RackTest driver for Capybara with remote request support
103
+ test_files: []