capybara-mechanize 1.10.1 → 1.12.1
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.
- checksums.yaml +5 -5
- data/README.mdown +24 -2
- data/lib/capybara/mechanize/browser.rb +41 -37
- data/lib/capybara/mechanize/cucumber.rb +3 -1
- data/lib/capybara/mechanize/driver.rb +9 -3
- data/lib/capybara/mechanize/form.rb +11 -20
- data/lib/capybara/mechanize/node.rb +8 -10
- data/lib/capybara/mechanize/version.rb +3 -1
- data/lib/capybara/mechanize.rb +6 -7
- data/lib/capybara/spec/extended_test_app.rb +19 -16
- data/spec/driver/mechanize_driver_spec.rb +72 -71
- data/spec/driver/remote_mechanize_driver_spec.rb +17 -15
- data/spec/session/mechanize_spec.rb +59 -43
- data/spec/session/remote_mechanize_spec.rb +57 -53
- data/spec/spec_helper.rb +4 -5
- data/spec/support/disable_external_tests.rb +4 -3
- data/spec/support/extended_test_app_setup.rb +2 -0
- data/spec/support/remote_test_url.rb +3 -1
- metadata +73 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d9de2bac559fc9346c178d9ca419cb01abf385dd4f918947b163f683f5a78f55
|
4
|
+
data.tar.gz: bfd5d3bf408fd0f4d3f695e9be255006b71e10fca7ca79668430c5e2fc1a2504
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96b828606020d6384de2faa8fa8ca3e3746f620b5baeda8fb1c2943d2b401e17236f24ad58049716389de9424b97e0d5be65ee662ece82ea71c0156a3352167b
|
7
|
+
data.tar.gz: 5747632a6fc871169ccd81960e62e53cc081c6dfdbff8fbc4cb6401f03ceada59e58a96bb2faa9f7a91035a704ed1cf97e9599bbffab97d31723ac16a978f197
|
data/README.mdown
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
Capybara-mechanize
|
2
2
|
==================
|
3
3
|
|
4
|
-
[](https://github.com/phillbaker/capybara-mechanize/actions/workflows/test_and_release.yml)
|
5
5
|
|
6
|
-
This
|
6
|
+
This gem makes it possible to use Capybara for (partially) remote testing. It inherits most functionality from the RackTest driver and only uses [Mechanize](https://github.com/sparklemotion/mechanize) for remote requests.
|
7
7
|
|
8
8
|
It is currently in use to test the integration between a Rails application and Twitter authorization and sharing.
|
9
9
|
|
@@ -15,6 +15,12 @@ Thanks to [Pinkelstar](http://www.pinkelstar.com) for giving me the time and the
|
|
15
15
|
|
16
16
|
gem install capybara-mechanize
|
17
17
|
|
18
|
+
### Compatibility
|
19
|
+
|
20
|
+
For support with:
|
21
|
+
* Capybara 2.x, use versions of this gem less than or equal 1.11.0
|
22
|
+
* Capybara 3.x, use versions of this gem greater than or equal to 1.12.0
|
23
|
+
|
18
24
|
### Usage without Cucumber
|
19
25
|
|
20
26
|
require 'capybara/mechanize'
|
@@ -35,7 +41,19 @@ Capybara.register_driver :mechanize do |app|
|
|
35
41
|
driver
|
36
42
|
end
|
37
43
|
```
|
44
|
+
### Usage without rack app
|
38
45
|
|
46
|
+
You can configure it to use for external servers. Until this issue https://github.com/jeroenvandijk/capybara-mechanize/issues/66 is resolved, you can configure with
|
47
|
+
```
|
48
|
+
Capybara.register_driver :mechanize do |app|
|
49
|
+
Capybara::Mechanize::Driver.new(proc {})
|
50
|
+
end
|
51
|
+
```
|
52
|
+
and use like this
|
53
|
+
```
|
54
|
+
session = Capybara::Session.new :mechanize
|
55
|
+
session.visit 'https://github.com'
|
56
|
+
```
|
39
57
|
### Usage with Cucumber and tags
|
40
58
|
|
41
59
|
A @mechanize tag is added to your hooks when you add the following line to your env.rb
|
@@ -56,6 +74,10 @@ When you want to use this driver to test a remote application. You have to set t
|
|
56
74
|
|
57
75
|
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.
|
58
76
|
|
77
|
+
### HTTP errors
|
78
|
+
|
79
|
+
If you receive the error `Net::HTTP::Persistent::Error: too many connection resets`, try setting a timeout value: `page.driver.browser.agent.idle_timeout = 0.4`.
|
80
|
+
|
59
81
|
## Running tests
|
60
82
|
|
61
83
|
Run bundler
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'capybara/rack_test/driver'
|
2
4
|
require 'mechanize'
|
3
5
|
require 'capybara/mechanize/node'
|
@@ -31,11 +33,15 @@ class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
|
|
31
33
|
last_request_remote? ? remote_response : super
|
32
34
|
end
|
33
35
|
|
36
|
+
def last_request
|
37
|
+
last_request_remote? ? OpenStruct.new(request_method: @last_method, params: @last_params) : super
|
38
|
+
end
|
39
|
+
|
34
40
|
# For each of these http methods, we want to intercept the method call.
|
35
41
|
# Then we determine if the call is remote or local.
|
36
42
|
# Remote: Handle it with our process_remote_request method.
|
37
43
|
# Local: Register the local request and call super to let RackTest get it.
|
38
|
-
[
|
44
|
+
%i[get post put delete].each do |method|
|
39
45
|
define_method(method) do |path, params = {}, env = {}, &block|
|
40
46
|
path = @last_path if path.nil? || path.empty?
|
41
47
|
|
@@ -77,7 +83,7 @@ class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
|
|
77
83
|
end
|
78
84
|
|
79
85
|
def find(format, selector)
|
80
|
-
if format
|
86
|
+
if format == :css
|
81
87
|
dom.css(selector, Capybara::RackTest::CSSHandlers.new)
|
82
88
|
else
|
83
89
|
dom.xpath(selector)
|
@@ -106,39 +112,37 @@ class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
|
|
106
112
|
end
|
107
113
|
|
108
114
|
def process_remote_request(method, url, attributes, headers)
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
@agent.send(method, url, attributes, headers)
|
121
|
-
end
|
122
|
-
elsif method == :get
|
123
|
-
if attributes.is_a? Mechanize::Form
|
124
|
-
submit_mechanize_form(url, attributes, headers)
|
125
|
-
else
|
126
|
-
referer = headers['HTTP_REFERER']
|
127
|
-
@agent.send(method, url, attributes, referer, headers)
|
128
|
-
end
|
115
|
+
return unless remote?(url)
|
116
|
+
|
117
|
+
uri = URI.parse(url)
|
118
|
+
@last_remote_uri = uri
|
119
|
+
url = uri.to_s
|
120
|
+
|
121
|
+
reset_cache!
|
122
|
+
begin
|
123
|
+
if method == :post
|
124
|
+
if attributes.is_a? Mechanize::Form
|
125
|
+
submit_mechanize_form(url, attributes, headers)
|
129
126
|
else
|
130
127
|
@agent.send(method, url, attributes, headers)
|
131
128
|
end
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
129
|
+
elsif method == :get
|
130
|
+
if attributes.is_a? Mechanize::Form
|
131
|
+
submit_mechanize_form(url, attributes, headers)
|
132
|
+
else
|
133
|
+
referer = headers['HTTP_REFERER']
|
134
|
+
@agent.send(method, url, attributes, referer, headers)
|
138
135
|
end
|
136
|
+
else
|
137
|
+
@agent.send(method, url, attributes, headers)
|
139
138
|
end
|
140
|
-
@
|
139
|
+
@errored_remote_response = nil
|
140
|
+
rescue Mechanize::ResponseCodeError => e
|
141
|
+
@errored_remote_response = e.page
|
142
|
+
|
143
|
+
raise "Received the following error for a #{method.to_s.upcase} request to #{url}: '#{e.message}'" if Capybara.raise_server_errors
|
141
144
|
end
|
145
|
+
@last_request_remote = true
|
142
146
|
end
|
143
147
|
|
144
148
|
def submit_mechanize_form(url, form, headers)
|
@@ -150,12 +154,12 @@ class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
|
|
150
154
|
if errored_remote_response
|
151
155
|
ResponseProxy.new(errored_remote_response)
|
152
156
|
elsif @agent.current_page
|
153
|
-
ResponseProxy.new(@agent.current_page)
|
157
|
+
ResponseProxy.new(@agent.current_page, current_fragment: @current_fragment)
|
154
158
|
end
|
155
159
|
end
|
156
160
|
|
157
161
|
def default_user_agent
|
158
|
-
|
162
|
+
'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'
|
159
163
|
end
|
160
164
|
|
161
165
|
class ResponseProxy
|
@@ -165,18 +169,21 @@ class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
|
|
165
169
|
|
166
170
|
attr_reader :page
|
167
171
|
|
168
|
-
def initialize(page)
|
172
|
+
def initialize(page, current_fragment: nil)
|
169
173
|
@page = page
|
174
|
+
@current_fragment = current_fragment
|
170
175
|
end
|
171
176
|
|
172
177
|
def current_url
|
173
|
-
page.uri.
|
178
|
+
uri = page.uri.dup
|
179
|
+
uri.fragment = @current_fragment if @current_fragment
|
180
|
+
uri.to_s
|
174
181
|
end
|
175
182
|
|
176
183
|
def headers
|
177
184
|
# Hax the content-type contains utf8, so Capybara specs are failing, need to ask mailinglist
|
178
185
|
headers = page.response
|
179
|
-
headers[
|
186
|
+
headers['content-type']&.gsub!(';charset=utf-8', '')
|
180
187
|
headers
|
181
188
|
end
|
182
189
|
|
@@ -191,8 +198,5 @@ class Capybara::Mechanize::Browser < Capybara::RackTest::Browser
|
|
191
198
|
def redirect?
|
192
199
|
status >= 300 && status < 400
|
193
200
|
end
|
194
|
-
|
195
201
|
end
|
196
|
-
|
197
202
|
end
|
198
|
-
|
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'capybara/mechanize/browser'
|
2
4
|
|
3
5
|
class Capybara::Mechanize::Driver < Capybara::RackTest::Driver
|
4
|
-
|
5
6
|
def initialize(app, **options)
|
6
|
-
raise ArgumentError,
|
7
|
+
raise ArgumentError, 'mechanize requires a rack application, but none was given' unless app
|
7
8
|
|
8
9
|
super
|
9
10
|
end
|
@@ -12,11 +13,16 @@ class Capybara::Mechanize::Driver < Capybara::RackTest::Driver
|
|
12
13
|
browser.remote?(url)
|
13
14
|
end
|
14
15
|
|
15
|
-
def configure
|
16
|
+
def configure
|
16
17
|
yield(browser.agent) if block_given?
|
17
18
|
end
|
18
19
|
|
19
20
|
def browser
|
20
21
|
@browser ||= Capybara::Mechanize::Browser.new(self)
|
21
22
|
end
|
23
|
+
|
24
|
+
def reset!
|
25
|
+
@browser.agent.shutdown
|
26
|
+
super
|
27
|
+
end
|
22
28
|
end
|
@@ -1,25 +1,20 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
class Capybara::Mechanize::Form < Capybara::RackTest::Form
|
3
4
|
def params(button)
|
4
|
-
|
5
|
-
return super
|
6
|
-
end
|
5
|
+
return super unless use_mechanize?
|
7
6
|
|
8
7
|
node = {}
|
9
8
|
# Create a fake form
|
10
9
|
class << node
|
11
|
-
def search(*
|
10
|
+
def search(*_args); []; end
|
12
11
|
end
|
13
12
|
|
14
13
|
node['method'] = button && button['formmethod']
|
15
14
|
|
16
15
|
node['method'] ||= (respond_to?(:request_method, true) ? request_method : method).to_s.upcase
|
17
16
|
|
18
|
-
|
19
|
-
node['enctype'] = 'multipart/form-data'
|
20
|
-
else
|
21
|
-
node['enctype'] = 'application/x-www-form-urlencoded'
|
22
|
-
end
|
17
|
+
node['enctype'] = multipart? ? 'multipart/form-data' : 'application/x-www-form-urlencoded'
|
23
18
|
|
24
19
|
@m_form = Mechanize::Form.new(node, nil, form_referer)
|
25
20
|
|
@@ -31,20 +26,16 @@ class Capybara::Mechanize::Form < Capybara::RackTest::Form
|
|
31
26
|
private
|
32
27
|
|
33
28
|
def merge_param!(params, key, value)
|
34
|
-
|
35
|
-
return super
|
36
|
-
end
|
29
|
+
return super unless use_mechanize?
|
37
30
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
return params
|
42
|
-
end
|
31
|
+
# Adding a nil value here will result in the form element existing with the empty string as its value.
|
32
|
+
# Instead don't add the form element at all.
|
33
|
+
return params if value.is_a? NilUploadedFile
|
43
34
|
|
44
35
|
if value.is_a? Rack::Test::UploadedFile
|
45
36
|
@m_form.enctype = 'multipart/form-data'
|
46
37
|
|
47
|
-
ul = Mechanize::Form::FileUpload.new({'name' => key.to_s}, value.original_filename)
|
38
|
+
ul = Mechanize::Form::FileUpload.new({ 'name' => key.to_s }, value.original_filename)
|
48
39
|
ul.mime_type = value.content_type
|
49
40
|
ul.file_data = (value.rewind; value.read)
|
50
41
|
|
@@ -53,7 +44,7 @@ class Capybara::Mechanize::Form < Capybara::RackTest::Form
|
|
53
44
|
return params
|
54
45
|
end
|
55
46
|
|
56
|
-
@m_form.fields << Mechanize::Form::Field.new({'name' => key.to_s}, value)
|
47
|
+
@m_form.fields << Mechanize::Form::Field.new({ 'name' => key.to_s }, value)
|
57
48
|
|
58
49
|
params
|
59
50
|
end
|
@@ -1,18 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Capybara::Mechanize::Node < Capybara::RackTest::Node
|
2
|
-
def click(keys = [],
|
3
|
-
raise ArgumentError,
|
4
|
+
def click(keys = [], **options)
|
5
|
+
raise ArgumentError, 'The mechanize driver does not support click options' unless keys.empty? && options.empty?
|
4
6
|
|
5
7
|
submits = respond_to?(:submits?) ? submits? :
|
6
|
-
((tag_name == 'input' and %w
|
7
|
-
((tag_name == 'button') and type.nil? or type ==
|
8
|
+
((tag_name == 'input' and %w[submit image].include?(type)) or
|
9
|
+
((tag_name == 'button') and type.nil? or type == 'submit'))
|
8
10
|
|
9
11
|
if tag_name == 'a' or tag_name == 'label' or
|
10
|
-
(tag_name == 'input' and %w
|
11
|
-
|
12
|
-
super
|
13
|
-
else
|
14
|
-
super()
|
15
|
-
end
|
12
|
+
(tag_name == 'input' and %w[checkbox radio].include?(type))
|
13
|
+
Capybara::VERSION > '3.0.0' ? super : super()
|
16
14
|
elsif submits
|
17
15
|
associated_form = form
|
18
16
|
Capybara::Mechanize::Form.new(driver, form).submit(self) if associated_form
|
data/lib/capybara/mechanize.rb
CHANGED
@@ -1,19 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'capybara'
|
2
4
|
|
3
5
|
module Capybara::Mechanize
|
4
6
|
class << self
|
5
|
-
|
6
7
|
# Host that should be considered local (includes default_host)
|
7
8
|
def local_hosts
|
8
9
|
@local_hosts ||= begin
|
9
|
-
default_host = URI.parse(Capybara.default_host ||
|
10
|
+
default_host = URI.parse(Capybara.default_host || '').host || Capybara.default_host
|
10
11
|
[default_host].compact
|
11
12
|
end
|
12
13
|
end
|
13
|
-
|
14
|
-
|
15
|
-
@local_hosts = hosts
|
16
|
-
end
|
14
|
+
|
15
|
+
attr_writer :local_hosts
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
@@ -21,4 +20,4 @@ require 'capybara/mechanize/driver'
|
|
21
20
|
|
22
21
|
Capybara.register_driver :mechanize do |app|
|
23
22
|
Capybara::Mechanize::Driver.new(app)
|
24
|
-
end
|
23
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'capybara/spec/test_app'
|
2
4
|
|
3
5
|
class ExtendedTestApp < TestApp
|
@@ -9,19 +11,19 @@ class ExtendedTestApp < TestApp
|
|
9
11
|
end
|
10
12
|
|
11
13
|
get '/form_with_relative_action_to_host' do
|
12
|
-
%
|
14
|
+
%(<form action="/request_info/host" method="post">
|
13
15
|
<input type="submit" value="submit" />
|
14
|
-
</form>
|
16
|
+
</form>)
|
15
17
|
end
|
16
18
|
|
17
19
|
get '/request_info/form_with_no_action' do
|
18
|
-
%
|
20
|
+
%(<form method="post">
|
19
21
|
<input type="submit" value="submit" />
|
20
|
-
</form>
|
22
|
+
</form>)
|
21
23
|
end
|
22
24
|
|
23
25
|
get '/relative_link_to_host' do
|
24
|
-
%
|
26
|
+
%(<a href="/request_info/host">host</a>)
|
25
27
|
end
|
26
28
|
|
27
29
|
get '/request_info/user_agent' do
|
@@ -37,15 +39,15 @@ class ExtendedTestApp < TestApp
|
|
37
39
|
end
|
38
40
|
|
39
41
|
get '/subsite/relative_link_to_host' do
|
40
|
-
%
|
42
|
+
%(<a href="/subsite/request_info2/host">host</a>)
|
41
43
|
end
|
42
44
|
|
43
45
|
get '/subsite/local_link_to_host' do
|
44
|
-
%
|
46
|
+
%(<a href="request_info2/host">host</a>)
|
45
47
|
end
|
46
48
|
|
47
49
|
get '/subsite/request_info2/*' do
|
48
|
-
|
50
|
+
'subsite: ' + current_request_info
|
49
51
|
end
|
50
52
|
|
51
53
|
get '/redirect_with_http_param' do
|
@@ -53,25 +55,26 @@ class ExtendedTestApp < TestApp
|
|
53
55
|
end
|
54
56
|
|
55
57
|
get '/redirect_target' do
|
56
|
-
%
|
58
|
+
%(correct redirect)
|
57
59
|
end
|
58
60
|
|
59
61
|
get %r{/form_posts_to/(.*)} do
|
60
|
-
%
|
62
|
+
%(
|
61
63
|
<form action="#{params[:captures].first}" method="post">
|
62
64
|
<input type="submit" value="submit" />
|
63
65
|
</form>
|
64
|
-
|
66
|
+
)
|
65
67
|
end
|
66
68
|
|
67
69
|
post '/get_referer' do
|
68
|
-
request.referer.nil? ?
|
70
|
+
request.referer.nil? ? 'No referer' : "Got referer: #{request.referer}"
|
69
71
|
end
|
70
72
|
|
73
|
+
@form_post_count = 0
|
74
|
+
|
71
75
|
private
|
72
76
|
|
73
|
-
|
74
|
-
|
75
|
-
|
77
|
+
def current_request_info
|
78
|
+
"Current host is #{request.url}, method #{request.request_method.downcase}"
|
79
|
+
end
|
76
80
|
end
|
77
|
-
|