ryansch-capybara-mechanize 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []