capybara-mechanize 0.3.0 → 0.4.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
data/README.mdown CHANGED
@@ -49,7 +49,6 @@ Then you are ready to run the test like so
49
49
 
50
50
  Todo
51
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
52
  * Test this driver with non-rack/non-ruby projects
54
53
 
55
54
  Note on Patches/Pull Requests
@@ -1,5 +1,7 @@
1
1
  require 'capybara/rack_test/driver'
2
2
  require 'mechanize'
3
+ require 'capybara/mechanize/node'
4
+ require 'capybara/mechanize/form'
3
5
 
4
6
  class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
5
7
  extend Forwardable
@@ -28,104 +30,22 @@ class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
28
30
  last_request_remote? ? remote_response : super
29
31
  end
30
32
 
31
- def follow_redirects!
32
- 5.times do
33
- follow_redirect! if last_response.redirect?
34
- end
35
- raise Capybara::InfiniteRedirectError, "redirected more than 5 times, check for infinite redirects." if last_response.redirect?
36
- end
37
-
38
- def follow_redirect!
39
- unless last_response.redirect?
40
- raise "Last response was not a redirect. Cannot follow_redirect!"
41
- end
42
-
43
- get(last_location_header)
44
- end
45
-
46
- def process(method, path, *options)
47
- reset_cache!
48
- send(method, path, *options)
49
- follow_redirects!
50
- end
51
-
52
- def process_without_redirect(method, path, attributes, headers)
53
- path = @last_path if path.nil? || path.empty?
54
-
55
- if remote?(path)
56
- process_remote_request(method, path, attributes, headers)
57
- else
58
- register_local_request
59
-
60
- path = determine_path(path)
61
-
62
- reset_cache!
63
- send("racktest_#{method}", path, attributes, env.merge(headers))
64
- end
65
-
66
- @last_path = path
67
- end
68
-
69
- # TODO path Capybara to move this into its own method
70
- def determine_path(path)
71
- new_uri = URI.parse(path)
72
- current_uri = URI.parse(current_url)
73
-
74
- if new_uri.host
75
- @current_host = new_uri.scheme + '://' + new_uri.host
76
- end
77
-
78
- if new_uri.relative?
79
- path = request_path + path if path.start_with?('?')
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?
80
40
 
81
- unless path.start_with?('/')
82
- folders = request_path.split('/')
83
- if folders.empty?
84
- path = '/' + path
85
- else
86
- path = (folders[0, folders.size - 1] << path).join('/')
87
- end
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)
88
46
  end
89
- path = current_host + path
90
- end
91
- path
92
- end
93
-
94
- alias :racktest_get :get
95
- def get(path, attributes = {}, headers = {})
96
- process_without_redirect(:get, path, attributes, headers)
97
- end
98
47
 
99
- alias :racktest_post :post
100
- def post(path, attributes = {}, headers = {})
101
- process_without_redirect(:post, path, post_data(attributes), headers)
102
- end
103
-
104
- alias :racktest_put :put
105
- def put(path, attributes = {}, headers = {})
106
- process_without_redirect(:put, path, attributes, headers)
107
- end
108
-
109
- alias :racktest_delete :delete
110
- def delete(path, attributes = {}, headers = {})
111
- process_without_redirect(:delete, path, attributes, headers)
112
- end
113
-
114
- def post_data(params)
115
- params.inject({}) do |memo, param|
116
- case param
117
- when Hash
118
- param.each {|attribute, value| memo[attribute] = value }
119
- memo
120
- when Array
121
- case param.last
122
- when Hash
123
- param.last.each {|attribute, value| memo["#{param.first}[#{attribute}]"] = value }
124
- else
125
- memo[param.first] = param.last
126
- end
127
- memo
128
- end
48
+ @last_path = path
129
49
  end
130
50
  end
131
51
 
@@ -143,14 +63,14 @@ class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
143
63
  end
144
64
  end
145
65
 
66
+ def find(selector)
67
+ dom.xpath(selector).map { |node| Capybara::Mechanize::Node.new(self, node) }
68
+ end
69
+
146
70
  attr_reader :agent
147
71
 
148
72
  private
149
73
 
150
- def last_location_header
151
- last_request_remote? ? remote_response.page.response['Location'] : last_response['Location']
152
- end
153
-
154
74
  def last_request_remote?
155
75
  !!@last_request_remote
156
76
  end
@@ -160,19 +80,38 @@ class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
160
80
  @last_request_remote = false
161
81
  end
162
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
+
163
91
  def process_remote_request(method, url, attributes, headers)
164
92
  if remote?(url)
165
93
  uri = URI.parse(url)
166
- uri = resolve_relative_url(url) if uri.host.nil?
167
94
  @last_remote_uri = uri
168
95
  url = uri.to_s
169
96
 
170
97
  reset_cache!
171
98
  begin
172
- args = []
173
- args << attributes unless attributes.empty?
174
- args << headers unless headers.empty?
175
- @agent.send(method, url, *args)
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
176
115
  rescue => e
177
116
  raise "Received the following error for a #{method.to_s.upcase} request to #{url}: '#{e.message}'"
178
117
  end
@@ -180,40 +119,11 @@ class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
180
119
  end
181
120
  end
182
121
 
183
- # paths are combined "intelligently" as close as they would be by the browser, but still interpreting
184
- # routes from rails like "/user/login" as relative to a host including a possible subdirectory:
185
- # eg: app_host = localhost/mysite/ url = / result = http://localhost/mysite/
186
- # eg: app_host = localhost/mysite/ url = /home result = http://localhost/mysite/home
187
- # eg: app_host = localhost/mysite/ url = /user/login result = http://localhost/mysite/user/login
188
- # eg: app_host = localhost/mysite/ url = /mysite/login result = http://localhost/mysite/login
189
- # **** notice that 'mysite' is not repeated! *****
190
- def resolve_relative_url(url)
191
- if @last_remote_uri
192
- base_uri = @last_remote_uri
193
- path_prefix = ''
194
- else
195
- host = Capybara.app_host || Capybara.default_host
196
- # do this in text so we don't get the host interpretted as the scheme.
197
- host = "http://#{host}" unless host =~ %r{^https?://.*}
198
- base_uri = URI.parse(host)
199
- base_uri.path = '/' if base_uri.path.nil? || base_uri.path.empty?
200
- if base_uri.path.length > 1
201
- path_prefix = base_uri.path
202
- path_prefix += '/' unless path_prefix.end_with?('/') || url.start_with?('/')
203
-
204
- # if the prefix is already in the path, don't let it be there twice.
205
- if url.start_with?(path_prefix)
206
- path_prefix = ''
207
- end
208
- else
209
- path_prefix = ''
210
- end
211
- end
212
- uri = URI.parse(path_prefix + url)
213
- result_uri = base_uri.merge uri
122
+ def submit_mechanize_form(url, form, headers)
123
+ form.action = url
124
+ @agent.submit(form, nil, headers)
214
125
  end
215
126
 
216
-
217
127
  def remote_response
218
128
  ResponseProxy.new(@agent.current_page) if @agent.current_page
219
129
  end
@@ -244,6 +154,10 @@ class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
244
154
  headers
245
155
  end
246
156
 
157
+ def [](key)
158
+ headers[key]
159
+ end
160
+
247
161
  def status
248
162
  page.code.to_i
249
163
  end
@@ -2,12 +2,10 @@ require 'capybara/mechanize/browser'
2
2
 
3
3
  class Capybara::Mechanize::Driver < Capybara::RackTest::Driver
4
4
 
5
- def initialize(app = nil, options = {})
6
- if !app && !Capybara.app_host
7
- raise ArgumentError, "You have to set at least Capybara.app_host or Capybara.app"
8
- end
5
+ def initialize(app, options = {})
6
+ raise ArgumentError, "mechanize requires a rack application, but none was given" unless app
9
7
 
10
- @app, @options = app, options
8
+ super
11
9
  end
12
10
 
13
11
  def remote?(url)
@@ -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
+ Mechanize::Page.new URI(driver.current_url)
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
@@ -1,5 +1,5 @@
1
1
  module Capybara
2
2
  module Mechanize
3
- VERSION = '0.3.0'
3
+ VERSION = '0.4.0.rc1'
4
4
  end
5
5
  end
@@ -2,9 +2,10 @@ require 'capybara/spec/test_app'
2
2
 
3
3
  class ExtendedTestApp < TestApp#< Sinatra::Base
4
4
  set :environment, :production # so we don't get debug info that makes our test pass!
5
+ disable :protection
5
6
 
6
7
  get %r{/redirect_to/(.*)} do
7
- redirect params[:captures]
8
+ redirect params[:captures].first
8
9
  end
9
10
 
10
11
  get '/form_with_relative_action_to_host' do
@@ -35,10 +36,6 @@ class ExtendedTestApp < TestApp#< Sinatra::Base
35
36
  current_request_info
36
37
  end
37
38
 
38
- get '/host' do
39
- "Current host is #{request.scheme}://#{request.host}:#{request.port}"
40
- end
41
-
42
39
  get '/subsite/relative_link_to_host' do
43
40
  %{<a href="/subsite/request_info2/host">host</a>}
44
41
  end
@@ -54,11 +51,23 @@ class ExtendedTestApp < TestApp#< Sinatra::Base
54
51
  get '/redirect_with_http_param' do
55
52
  redirect '/redirect_target?foo=http'
56
53
  end
57
-
54
+
58
55
  get '/redirect_target' do
59
56
  %{correct redirect}
60
57
  end
61
58
 
59
+ get %r{/form_posts_to/(.*)} do
60
+ %{
61
+ <form action="#{params[:captures].first}" method="post">
62
+ <input type="submit" value="submit" />
63
+ </form>
64
+ }
65
+ end
66
+
67
+ post '/get_referer' do
68
+ request.referer.nil? ? "No referer" : "Got referer: #{request.referer}"
69
+ end
70
+
62
71
  private
63
72
 
64
73
  def current_request_info
@@ -1,151 +1,215 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "Capybara::Driver::Mechanize, in local model" do
4
- before do
5
- @driver = Capybara::Mechanize::Driver.new(ExtendedTestApp)
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
6
50
  end
7
-
8
- it "should throw an error when no rack app is given without an app host" do
9
- running do
10
- Capybara::Mechanize::Driver.new
11
- end.should raise_error(ArgumentError, "You have to set at least Capybara.app_host or Capybara.app")
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
12
82
  end
13
-
14
- it_should_behave_like "driver"
15
- it_should_behave_like "driver with header support"
16
- it_should_behave_like "driver with status code support"
17
- it_should_behave_like "driver with cookies support"
18
- it_should_behave_like "driver with infinite redirect detection"
19
83
 
20
84
  it "should default to local mode for relative paths" do
21
- @driver.should_not be_remote('/')
85
+ driver.should_not be_remote('/')
22
86
  end
23
-
87
+
24
88
  it "should default to local mode for the default host" do
25
- @driver.should_not be_remote('http://www.example.com')
89
+ driver.should_not be_remote('http://www.example.com')
26
90
  end
27
91
 
28
92
  context "with an app_host" do
29
-
93
+
30
94
  before do
31
95
  Capybara.app_host = 'http://www.remote.com'
32
96
  end
33
-
97
+
34
98
  after do
35
99
  Capybara.app_host = nil
36
100
  end
37
101
 
38
102
  it "should treat urls as remote" do
39
- @driver.should be_remote('http://www.remote.com')
103
+ driver.should be_remote('http://www.remote.com')
40
104
  end
41
105
  end
42
106
 
43
107
  context "with a default url, no app host" do
44
- before :each do
108
+ before do
45
109
  Capybara.default_host = 'www.local.com'
46
110
  end
47
-
111
+
48
112
  it "should allow local hosts to be set" do
49
113
  Capybara::Mechanize.local_hosts = ['subdomain.local.com']
50
- @driver.should_not be_remote('http://subdomain.local.com')
114
+ driver.should_not be_remote('http://subdomain.local.com')
51
115
  end
52
-
116
+
53
117
  it "should treat urls with the same host names as local" do
54
- @driver.should_not be_remote('http://www.local.com')
118
+ driver.should_not be_remote('http://www.local.com')
55
119
  end
56
-
120
+
57
121
  it "should treat other urls as remote" do
58
- @driver.should be_remote('http://www.remote.com')
122
+ driver.should be_remote('http://www.remote.com')
59
123
  end
60
-
124
+
61
125
  it "should treat relative paths as remote if the previous request was remote" do
62
- @driver.visit(REMOTE_TEST_URL)
63
- @driver.should be_remote('/some_relative_link')
126
+ driver.visit(REMOTE_TEST_URL)
127
+ driver.should be_remote('/some_relative_link')
64
128
  end
65
129
 
66
130
  it "should treat relative paths as local if the previous request was local" do
67
- @driver.visit('http://www.local.com')
68
- @driver.should_not be_remote('/some_relative_link')
131
+ driver.visit('http://www.local.com')
132
+ driver.should_not be_remote('/some_relative_link')
69
133
  end
70
134
 
71
135
  it "should receive the right host" do
72
- @driver.visit('http://www.local.com/host')
136
+ driver.visit('http://www.local.com/host')
73
137
  should_be_a_local_get
74
138
  end
75
139
 
76
140
  it "should consider relative paths to be local when the previous request was local" do
77
- @driver.visit('http://www.local.com/host')
78
- @driver.visit('/host')
141
+ driver.visit('http://www.local.com/host')
142
+ driver.visit('/host')
79
143
 
80
144
  should_be_a_local_get
81
- @driver.should_not be_remote('/first_local')
145
+ driver.should_not be_remote('/first_local')
82
146
  end
83
-
147
+
84
148
  it "should consider relative paths to be remote when the previous request was remote" do
85
- @driver.visit("#{REMOTE_TEST_URL}/host")
86
- @driver.get('/host')
149
+ driver.visit("#{REMOTE_TEST_URL}/host")
150
+ driver.get('/host')
87
151
 
88
152
  should_be_a_remote_get
89
- @driver.should be_remote('/second_remote')
153
+ driver.should be_remote('/second_remote')
90
154
  end
91
-
155
+
92
156
  it "should always switch to the right context" do
93
- @driver.visit('http://www.local.com/host')
94
- @driver.get('/host')
95
- @driver.get("#{REMOTE_TEST_URL}/host")
96
- @driver.get('/host')
97
- @driver.get('http://www.local.com/host')
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')
98
162
 
99
163
  should_be_a_local_get
100
- @driver.should_not be_remote('/second_local')
164
+ driver.should_not be_remote('/second_local')
101
165
  end
102
166
 
103
167
  it "should follow redirects from local to remote" do
104
- @driver.visit("http://www.local.com/redirect_to/#{REMOTE_TEST_URL}/host")
168
+ driver.visit("http://www.local.com/redirect_to/#{REMOTE_TEST_URL}/host")
105
169
  should_be_a_remote_get
106
170
  end
107
-
171
+
108
172
  it "should follow redirects from remote to local" do
109
- @driver.visit("#{REMOTE_TEST_URL}/redirect_to/http://www.local.com/host")
173
+ driver.visit("#{REMOTE_TEST_URL}/redirect_to/http://www.local.com/host")
110
174
  should_be_a_local_get
111
175
  end
112
-
113
- after :each do
176
+
177
+ after do
114
178
  Capybara.default_host = nil
115
179
  end
116
-
180
+
117
181
  it "should raise a useful error for sites that return a 404, because it is probably a misconfiguration" do
118
- lambda {
119
- @driver.visit("http://iamreallysurethatthisdoesntexist.com/canttouchthis")
120
- }.should raise_error(%r{Received the following error for a GET request to http://iamreallysurethatthisdoesntexist.com/canttouchthis:})
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:})
121
185
  end
122
186
  end
123
187
 
124
188
  it "should include the right host when remote" do
125
- @driver.visit("#{REMOTE_TEST_URL}/host")
189
+ driver.visit("#{REMOTE_TEST_URL}/host")
126
190
  should_be_a_remote_get
127
191
  end
128
192
 
129
193
  describe '#reset!' do
130
- before :each do
194
+ before do
131
195
  Capybara.default_host = 'http://www.local.com'
132
196
  end
133
197
 
134
198
  it 'should reset remote host' do
135
- @driver.visit("#{REMOTE_TEST_URL}/host")
199
+ driver.visit("#{REMOTE_TEST_URL}/host")
136
200
  should_be_a_remote_get
137
- @driver.reset!
138
- @driver.visit("/host")
201
+ driver.reset!
202
+ driver.visit("/host")
139
203
  should_be_a_local_get
140
204
  end
141
205
  end
142
206
 
143
207
  def should_be_a_remote_get
144
- @driver.body.should include(REMOTE_TEST_URL)
208
+ driver.current_url.should include(REMOTE_TEST_URL)
145
209
  end
146
-
210
+
147
211
  def should_be_a_local_get
148
- @driver.body.should include("www.local.com")
212
+ driver.current_url.should include("www.local.com")
149
213
  end
150
-
214
+ #
151
215
  end
@@ -1,65 +1,46 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Capybara::Mechanize::Driver do
4
- before(:each) do
3
+ describe Capybara::Mechanize::Driver, 'remote' do
4
+ before do
5
5
  Capybara.app_host = REMOTE_TEST_URL
6
6
  end
7
-
8
- after(:each) do
7
+
8
+ after do
9
9
  Capybara.app_host = nil
10
10
  end
11
11
 
12
- before do
13
- @driver = Capybara::Mechanize::Driver.new
14
- end
15
-
12
+ let(:driver) { Capybara::Mechanize::Driver.new(ExtendedTestApp) }
13
+
16
14
  context "in remote mode" do
17
- it "should not throw an error when no rack app is given" do
18
- running do
19
- Capybara::Mechanize::Driver.new
20
- end.should_not raise_error(ArgumentError)
21
- end
22
-
23
15
  it "should pass arguments through to a get request" do
24
- @driver.visit("#{REMOTE_TEST_URL}/form/get", {:form => "success"})
25
- @driver.body.should include('success')
16
+ driver.visit("#{REMOTE_TEST_URL}/form/get", {:form => "success"})
17
+ driver.html.should include('success')
26
18
  end
27
19
 
28
20
  it "should pass arguments through to a post request" do
29
- @driver.post("#{REMOTE_TEST_URL}/form", {:form => "success"})
30
- @driver.body.should include('success')
21
+ driver.post("#{REMOTE_TEST_URL}/form", {:form => "success"})
22
+ driver.html.should include('success')
31
23
  end
32
24
 
33
- context "for a post request" do
34
-
35
- it "should transform nested map in post data" do
36
- @driver.post("#{REMOTE_TEST_URL}/form", {:form => {:key => "value"}})
37
- @driver.body.should include('key: value')
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')
38
29
  end
39
-
40
30
  end
41
31
 
42
- context "process remote request" do
43
-
44
- it "should transform nested map in post data" do
45
- @driver.submit(:post, "#{REMOTE_TEST_URL}/form", {:form => {:key => "value"}})
46
- @driver.body.should include('key: value')
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"')
47
36
  end
48
-
49
37
  end
50
38
 
51
- describe "redirect" do
52
- it "should handle redirects with http-params" do
53
- @driver.visit "#{REMOTE_TEST_URL}/redirect_with_http_param"
54
- @driver.body.should include('correct redirect')
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"')
55
43
  end
56
44
  end
57
-
58
- it_should_behave_like "driver"
59
- it_should_behave_like "driver with header support"
60
- it_should_behave_like "driver with status code support"
61
- it_should_behave_like "driver with cookies support"
62
- it_should_behave_like "driver with infinite redirect detection"
63
45
  end
64
-
65
46
  end
@@ -1,59 +1,103 @@
1
1
  require 'spec_helper'
2
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
+
3
15
  describe Capybara::Session do
4
16
  context 'with mechanize driver' do
17
+ let(:session) { Capybara::Session.new(:mechanize, ExtendedTestApp) }
18
+
5
19
  before do
6
- @session = Capybara::Session.new(:mechanize, TestApp)
7
- @session.driver.options[:respect_data_method] = true
8
20
  Capybara.default_host = 'http://www.local.com'
9
21
  end
10
22
 
11
23
  describe '#driver' do
12
24
  it "should be a mechanize driver" do
13
- @session.driver.should be_an_instance_of(Capybara::Mechanize::Driver)
25
+ session.driver.should be_an_instance_of(Capybara::Mechanize::Driver)
14
26
  end
15
27
  end
16
28
 
17
29
  describe '#mode' do
18
30
  it "should remember the mode" do
19
- @session.mode.should == :mechanize
31
+ session.mode.should == :mechanize
20
32
  end
21
33
  end
22
34
 
23
35
  describe '#click_link' do
24
- it "should use data-method if available" do
25
- @session.visit "/with_html"
26
- @session.click_link "A link with data-method"
27
- @session.body.should include('The requested object was deleted')
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
28
69
  end
29
70
  end
30
71
 
31
72
  it "should use the last remote url when following relative links" do
32
- @session.visit("#{REMOTE_TEST_URL}/relative_link_to_host")
33
- @session.click_link "host"
34
- @session.body.should include("Current host is #{REMOTE_TEST_URL}/request_info/host, method get")
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")
35
76
  end
36
77
 
37
78
  it "should use the last remote url when submitting a form with a relative action" do
38
- @session.visit("#{REMOTE_TEST_URL}/form_with_relative_action_to_host")
39
- @session.click_button "submit"
40
- @session.body.should include("Current host is #{REMOTE_TEST_URL}/request_info/host, method post")
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")
41
82
  end
42
83
 
43
84
  it "should use the last url when submitting a form with no action" do
44
- @session.visit("#{REMOTE_TEST_URL}/request_info/form_with_no_action")
45
- @session.click_button "submit"
46
- @session.body.should include("Current host is #{REMOTE_TEST_URL}/request_info/form_with_no_action, method post")
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")
47
88
  end
48
89
 
49
90
  it "should send correct user agent" do
50
- @session.visit("#{REMOTE_TEST_URL}/request_info/user_agent")
51
- @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")
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")
52
93
  end
53
94
 
54
- it_should_behave_like "session"
55
- it_should_behave_like "session without javascript support"
56
- it_should_behave_like "session with headers support"
57
- it_should_behave_like "session with status code support"
95
+ context 'form referer when switching from local to remote' do
96
+ it 'sends the referer' do
97
+ session.visit "/form_posts_to/#{REMOTE_TEST_URL}/get_referer"
98
+ session.click_button 'submit'
99
+ session.body.should include 'Got referer'
100
+ end
101
+ end
58
102
  end
59
103
  end
@@ -1,66 +1,102 @@
1
1
  require 'spec_helper'
2
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
+
3
34
  describe Capybara::Session do
4
35
  context 'with remote mechanize driver' do
5
- before(:each) do
6
- Capybara.app_host = REMOTE_TEST_URL
7
- end
36
+ include_context 'remote tests'
8
37
 
9
- after(:each) do
10
- Capybara.app_host = nil
11
- end
12
-
13
-
14
- before do
15
- @session = Capybara::Session.new(:mechanize)
16
- @session.driver.options[:respect_data_method] = true
17
- end
38
+ let(:session) { Capybara::Session.new(:mechanize, ExtendedTestApp) }
18
39
 
19
40
  describe '#driver' do
20
41
  it "should be a mechanize driver" do
21
- @session.driver.should be_an_instance_of(Capybara::Mechanize::Driver)
42
+ session.driver.should be_an_instance_of(Capybara::Mechanize::Driver)
22
43
  end
23
44
  end
24
45
 
25
46
  describe '#mode' do
26
47
  it "should remember the mode" do
27
- @session.mode.should == :mechanize
48
+ session.mode.should == :mechanize
28
49
  end
29
50
  end
30
51
 
31
52
  describe '#click_link' do
32
- it "should use data-method if available" do
33
- @session.visit "/with_html"
34
- @session.click_link "A link with data-method"
35
- @session.body.should include('The requested object was deleted')
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')
36
58
  end
37
- end
38
-
39
-
40
59
 
41
- # Pending: Still 16 failing tests here (result is 706 examples, 16 failures, instead of 385 examples)
42
- # it_should_behave_like "session"
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
43
66
 
44
- it_should_behave_like "session without javascript support"
45
- it_should_behave_like "session with headers support"
46
- it_should_behave_like "session with status code support"
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
47
73
 
74
+ after do
75
+ session.driver.options[:respect_data_method] = false
76
+ end
77
+ end
48
78
 
49
- context "remote app in a sub-domain" do
50
- before :each do
51
- Capybara.app_host = "#{REMOTE_TEST_URL}/subsite"
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
52
86
  end
87
+ end
53
88
 
89
+ context "remote app in a sub-path" do
54
90
  it "follows relative link correctly" do
55
- @session.visit "/relative_link_to_host"
56
- @session.click_link "host"
57
- @session.body.should include('request_info2/host')
91
+ session.visit "/subsite/relative_link_to_host"
92
+ session.click_link "host"
93
+ session.body.should include('request_info2/host')
58
94
  end
59
95
 
60
96
  it "follows local link correctly" do
61
- @session.visit "/local_link_to_host"
62
- @session.click_link "host"
63
- @session.body.should include('request_info2/host')
97
+ session.visit "/subsite/local_link_to_host"
98
+ session.click_link "host"
99
+ session.body.should include('request_info2/host')
64
100
  end
65
101
  end
66
102
  end
data/spec/spec_helper.rb CHANGED
@@ -1,47 +1,28 @@
1
- require 'bundler/setup'
2
- require 'capybara'
3
- require 'capybara/dsl'
1
+ require 'capybara/spec/spec_helper'
4
2
  require 'capybara/mechanize'
5
3
  require 'capybara/spec/extended_test_app'
6
4
 
7
- require 'sinatra'
5
+ PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..')).freeze
8
6
 
9
- # TODO move this stuff into capybara
10
- require 'capybara/spec/driver'
11
- require 'capybara/spec/session'
7
+ $LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
12
8
 
13
- alias :running :lambda
9
+ Dir[File.join(PROJECT_ROOT, 'spec', 'support', '**', '*.rb')].each { |file| require(file) }
14
10
 
15
- Capybara.default_wait_time = 0 # less timeout so tests run faster
16
- Capybara.app = ExtendedTestApp
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
17
16
 
18
- rack_server = Capybara::Server.new(Capybara.app)
19
- rack_server.boot
17
+ # Used with DisableExternalTests
18
+ config.filter_run_excluding :external_test_disabled
20
19
 
21
- RSpec.configure do |config|
22
20
  config.after do
23
- Capybara.default_selector = :xpath
24
21
  Capybara::Mechanize.local_hosts = nil
25
22
  end
26
- # config.filter_run :focus => true
27
- end
28
-
29
- REMOTE_TEST_URL = "http://localhost:#{rack_server.port}"
30
23
 
31
-
32
-
33
- # for testing private methods, courtesy of
34
- # http://kailuowang.blogspot.com.au/2010/08/testing-private-methods-in-rspec.html
35
- def describe_internally *args, &block
36
- example = describe *args, &block
37
- klass = args[0]
38
- if klass.is_a? Class
39
- saved_private_instance_methods = klass.private_instance_methods
40
- example.before do
41
- klass.class_eval { public *saved_private_instance_methods }
42
- end
43
- example.after do
44
- klass.class_eval { private *saved_private_instance_methods }
45
- end
46
- end
24
+ Capybara::SpecHelper.configure(config)
47
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.find{ |g| g.description == description }
12
+ end
13
+
14
+ example = example_group.examples.find{ |e| e.description == example_description }
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 CHANGED
@@ -1,38 +1,54 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-mechanize
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
5
- prerelease:
4
+ version: 0.4.0.rc1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jeroen van Dijk
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-14 00:00:00.000000000Z
12
+ date: 2013-02-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mechanize
16
- requirement: &70180442685720 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: '2.3'
21
+ version: '2.5'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70180442685720
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.5'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: capybara
27
- requirement: &70180442685240 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ~>
31
36
  - !ruby/object:Gem::Version
32
- version: '1.1'
37
+ version: '2.0'
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.1
33
41
  type: :runtime
34
42
  prerelease: false
35
- version_requirements: *70180442685240
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
36
52
  description: RackTest driver for Capybara, but with remote request support thanks
37
53
  to mechanize
38
54
  email: jeroen@jeevidee.nl
@@ -43,15 +59,18 @@ files:
43
59
  - lib/capybara/mechanize/browser.rb
44
60
  - lib/capybara/mechanize/cucumber.rb
45
61
  - lib/capybara/mechanize/driver.rb
62
+ - lib/capybara/mechanize/form.rb
63
+ - lib/capybara/mechanize/node.rb
46
64
  - lib/capybara/mechanize/version.rb
47
65
  - lib/capybara/mechanize.rb
48
66
  - lib/capybara/spec/extended_test_app.rb
49
67
  - spec/driver/mechanize_driver_spec.rb
50
68
  - spec/driver/remote_mechanize_driver_spec.rb
51
- - spec/relative_urls_spec.rb
52
69
  - spec/session/mechanize_spec.rb
53
70
  - spec/session/remote_mechanize_spec.rb
54
71
  - spec/spec_helper.rb
72
+ - spec/support/disable_external_tests.rb
73
+ - spec/support/extended_test_app_setup.rb
55
74
  - README.mdown
56
75
  homepage: https://github.com/jeroenvandijk/capybara-mechanize
57
76
  licenses: []
@@ -74,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
74
93
  version: '0'
75
94
  requirements: []
76
95
  rubyforge_project:
77
- rubygems_version: 1.8.15
96
+ rubygems_version: 1.8.24
78
97
  signing_key:
79
98
  specification_version: 3
80
99
  summary: RackTest driver for Capybara with remote request support
@@ -1,68 +0,0 @@
1
- require "rspec"
2
- require 'capybara'
3
- require 'capybara/mechanize/browser'
4
- require File.expand_path('../spec_helper.rb', __FILE__)
5
-
6
- describe_internally Capybara::Mechanize::Browser do
7
- describe "Resolving Relative URLs" do
8
-
9
- before(:all) do
10
- @original_app_host = Capybara.app_host
11
- @driver = Object.new
12
- @browser = Capybara::Mechanize::Browser.new(@driver)
13
- end
14
-
15
- after(:all) do
16
- Capybara.app_host = @original_app_host
17
- @browser.reset_host!
18
- end
19
-
20
- context "resolving on 'http://localhost'" do
21
- before(:all) do
22
- Capybara.app_host ='http://localhost'
23
- end
24
-
25
- it "resolves '/'" do
26
- @browser.resolve_relative_url('/').to_s.should == 'http://localhost/'
27
- end
28
-
29
- it "resolves '/home'" do
30
- @browser.resolve_relative_url('/home').to_s.should == 'http://localhost/home'
31
- end
32
-
33
- it "resolves 'home'" do
34
- @browser.resolve_relative_url('home').to_s.should == 'http://localhost/home'
35
- end
36
-
37
- it "resolves 'user/login'" do
38
- @browser.resolve_relative_url('user/login').to_s.should == 'http://localhost/user/login'
39
- end
40
- end
41
-
42
- context "resolving on 'http://localhost/subsite'" do
43
- before() do
44
- Capybara.app_host='http://localhost/subsite'
45
- end
46
-
47
- it "resolves '/'" do
48
- @browser.resolve_relative_url('/').to_s.should == 'http://localhost/subsite/'
49
- end
50
-
51
- it "resolves '/home'" do
52
- @browser.resolve_relative_url('/home').to_s.should == 'http://localhost/subsite/home'
53
- end
54
-
55
- it "resolves 'home'" do
56
- @browser.resolve_relative_url('home').to_s.should == 'http://localhost/subsite/home'
57
- end
58
-
59
- it "resolves 'user/login'" do
60
- @browser.resolve_relative_url('user/login').to_s.should == 'http://localhost/subsite/user/login'
61
- end
62
-
63
- it "resolves '/subsite/user/login'" do
64
- @browser.resolve_relative_url('/subsite/user/login').to_s.should == 'http://localhost/subsite/user/login'
65
- end
66
- end
67
- end
68
- end