bbc-capybara 1.1.2
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/History.txt +325 -0
- data/License.txt +22 -0
- data/README.md +815 -0
- data/lib/capybara.rb +368 -0
- data/lib/capybara/cucumber.rb +25 -0
- data/lib/capybara/driver/base.rb +64 -0
- data/lib/capybara/driver/node.rb +74 -0
- data/lib/capybara/dsl.rb +50 -0
- data/lib/capybara/node/actions.rb +146 -0
- data/lib/capybara/node/base.rb +63 -0
- data/lib/capybara/node/document.rb +25 -0
- data/lib/capybara/node/element.rb +201 -0
- data/lib/capybara/node/finders.rb +154 -0
- data/lib/capybara/node/matchers.rb +442 -0
- data/lib/capybara/node/simple.rb +132 -0
- data/lib/capybara/query.rb +63 -0
- data/lib/capybara/rack_test/browser.rb +126 -0
- data/lib/capybara/rack_test/driver.rb +80 -0
- data/lib/capybara/rack_test/form.rb +80 -0
- data/lib/capybara/rack_test/node.rb +121 -0
- data/lib/capybara/rails.rb +17 -0
- data/lib/capybara/rspec.rb +26 -0
- data/lib/capybara/rspec/features.rb +22 -0
- data/lib/capybara/rspec/matchers.rb +152 -0
- data/lib/capybara/selector.rb +156 -0
- data/lib/capybara/selenium/driver.rb +169 -0
- data/lib/capybara/selenium/node.rb +91 -0
- data/lib/capybara/server.rb +87 -0
- data/lib/capybara/session.rb +322 -0
- data/lib/capybara/spec/driver.rb +329 -0
- data/lib/capybara/spec/fixtures/capybara.jpg +3 -0
- data/lib/capybara/spec/fixtures/test_file.txt +1 -0
- data/lib/capybara/spec/public/jquery-ui.js +791 -0
- data/lib/capybara/spec/public/jquery.js +9046 -0
- data/lib/capybara/spec/public/test.js +43 -0
- data/lib/capybara/spec/session.rb +148 -0
- data/lib/capybara/spec/session/all_spec.rb +78 -0
- data/lib/capybara/spec/session/attach_file_spec.rb +76 -0
- data/lib/capybara/spec/session/check_spec.rb +68 -0
- data/lib/capybara/spec/session/choose_spec.rb +29 -0
- data/lib/capybara/spec/session/click_button_spec.rb +305 -0
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +37 -0
- data/lib/capybara/spec/session/click_link_spec.rb +120 -0
- data/lib/capybara/spec/session/current_url_spec.rb +83 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +127 -0
- data/lib/capybara/spec/session/find_button_spec.rb +18 -0
- data/lib/capybara/spec/session/find_by_id_spec.rb +18 -0
- data/lib/capybara/spec/session/find_field_spec.rb +26 -0
- data/lib/capybara/spec/session/find_link_spec.rb +19 -0
- data/lib/capybara/spec/session/find_spec.rb +168 -0
- data/lib/capybara/spec/session/first_spec.rb +105 -0
- data/lib/capybara/spec/session/has_button_spec.rb +32 -0
- data/lib/capybara/spec/session/has_css_spec.rb +243 -0
- data/lib/capybara/spec/session/has_field_spec.rb +192 -0
- data/lib/capybara/spec/session/has_link_spec.rb +37 -0
- data/lib/capybara/spec/session/has_select_spec.rb +129 -0
- data/lib/capybara/spec/session/has_selector_spec.rb +129 -0
- data/lib/capybara/spec/session/has_table_spec.rb +34 -0
- data/lib/capybara/spec/session/has_text_spec.rb +138 -0
- data/lib/capybara/spec/session/has_xpath_spec.rb +123 -0
- data/lib/capybara/spec/session/headers.rb +19 -0
- data/lib/capybara/spec/session/javascript.rb +312 -0
- data/lib/capybara/spec/session/response_code.rb +19 -0
- data/lib/capybara/spec/session/select_spec.rb +119 -0
- data/lib/capybara/spec/session/text_spec.rb +24 -0
- data/lib/capybara/spec/session/uncheck_spec.rb +21 -0
- data/lib/capybara/spec/session/unselect_spec.rb +67 -0
- data/lib/capybara/spec/session/within_spec.rb +178 -0
- data/lib/capybara/spec/test_app.rb +156 -0
- data/lib/capybara/spec/views/buttons.erb +4 -0
- data/lib/capybara/spec/views/fieldsets.erb +29 -0
- data/lib/capybara/spec/views/form.erb +366 -0
- data/lib/capybara/spec/views/frame_one.erb +8 -0
- data/lib/capybara/spec/views/frame_two.erb +8 -0
- data/lib/capybara/spec/views/header_links.erb +7 -0
- data/lib/capybara/spec/views/host_links.erb +12 -0
- data/lib/capybara/spec/views/popup_one.erb +8 -0
- data/lib/capybara/spec/views/popup_two.erb +8 -0
- data/lib/capybara/spec/views/postback.erb +13 -0
- data/lib/capybara/spec/views/tables.erb +62 -0
- data/lib/capybara/spec/views/with_html.erb +75 -0
- data/lib/capybara/spec/views/with_html_entities.erb +1 -0
- data/lib/capybara/spec/views/with_js.erb +53 -0
- data/lib/capybara/spec/views/with_scope.erb +36 -0
- data/lib/capybara/spec/views/with_simple_html.erb +1 -0
- data/lib/capybara/spec/views/within_frames.erb +10 -0
- data/lib/capybara/spec/views/within_popups.erb +25 -0
- data/lib/capybara/util/save_and_open_page.rb +45 -0
- data/lib/capybara/util/timeout.rb +27 -0
- data/lib/capybara/version.rb +3 -0
- data/spec/basic_node_spec.rb +89 -0
- data/spec/capybara_spec.rb +46 -0
- data/spec/driver/rack_test_driver_spec.rb +90 -0
- data/spec/driver/selenium_driver_spec.rb +55 -0
- data/spec/dsl_spec.rb +255 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +8 -0
- data/spec/fixtures/selenium_driver_rspec_success.rb +8 -0
- data/spec/rspec/features_spec.rb +43 -0
- data/spec/rspec/matchers_spec.rb +564 -0
- data/spec/rspec_spec.rb +51 -0
- data/spec/save_and_open_page_spec.rb +155 -0
- data/spec/server_spec.rb +74 -0
- data/spec/session/rack_test_session_spec.rb +61 -0
- data/spec/session/selenium_session_spec.rb +26 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/timeout_spec.rb +28 -0
- metadata +297 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
module Capybara
|
|
2
|
+
module Node
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
#
|
|
6
|
+
# A {Capybara::Node::Simple} is a simpler version of {Capybara::Node::Base} which
|
|
7
|
+
# includes only {Capybara::Node::Finders} and {Capybara::Node::Matchers} and does
|
|
8
|
+
# not include {Capybara::Node::Actions}. This type of node is returned when
|
|
9
|
+
# using {Capybara.string}.
|
|
10
|
+
#
|
|
11
|
+
# It is useful in that it does not require a session, an application or a driver,
|
|
12
|
+
# but can still use Capybara's finders and matchers on any string that contains HTML.
|
|
13
|
+
#
|
|
14
|
+
class Simple
|
|
15
|
+
include Capybara::Node::Finders
|
|
16
|
+
include Capybara::Node::Matchers
|
|
17
|
+
|
|
18
|
+
attr_reader :native
|
|
19
|
+
|
|
20
|
+
def initialize(native)
|
|
21
|
+
native = Nokogiri::HTML(native) if native.is_a?(String)
|
|
22
|
+
@native = native
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
#
|
|
27
|
+
# @return [String] The text of the element
|
|
28
|
+
#
|
|
29
|
+
def text
|
|
30
|
+
native.text
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
#
|
|
35
|
+
# Retrieve the given attribute
|
|
36
|
+
#
|
|
37
|
+
# element[:title] # => HTML title attribute
|
|
38
|
+
#
|
|
39
|
+
# @param [Symbol] attribute The attribute to retrieve
|
|
40
|
+
# @return [String] The value of the attribute
|
|
41
|
+
#
|
|
42
|
+
def [](name)
|
|
43
|
+
attr_name = name.to_s
|
|
44
|
+
if attr_name == 'value'
|
|
45
|
+
value
|
|
46
|
+
elsif 'input' == tag_name and 'checkbox' == native[:type] and 'checked' == attr_name
|
|
47
|
+
native['checked'] == 'checked'
|
|
48
|
+
else
|
|
49
|
+
native[attr_name]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
#
|
|
55
|
+
# @return [String] The tag name of the element
|
|
56
|
+
#
|
|
57
|
+
def tag_name
|
|
58
|
+
native.node_name
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
##
|
|
62
|
+
#
|
|
63
|
+
# An XPath expression describing where on the page the element can be found
|
|
64
|
+
#
|
|
65
|
+
# @return [String] An XPath expression
|
|
66
|
+
#
|
|
67
|
+
def path
|
|
68
|
+
native.path
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
##
|
|
72
|
+
#
|
|
73
|
+
# @return [String] The value of the form element
|
|
74
|
+
#
|
|
75
|
+
def value
|
|
76
|
+
if tag_name == 'textarea'
|
|
77
|
+
native.content
|
|
78
|
+
elsif tag_name == 'select'
|
|
79
|
+
if native['multiple'] == 'multiple'
|
|
80
|
+
native.xpath(".//option[@selected='selected']").map { |option| option[:value] || option.content }
|
|
81
|
+
else
|
|
82
|
+
option = native.xpath(".//option[@selected='selected']").first || native.xpath(".//option").first
|
|
83
|
+
option[:value] || option.content if option
|
|
84
|
+
end
|
|
85
|
+
else
|
|
86
|
+
native[:value]
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
##
|
|
91
|
+
#
|
|
92
|
+
# Whether or not the element is visible. Does not support CSS, so
|
|
93
|
+
# the result may be inaccurate.
|
|
94
|
+
#
|
|
95
|
+
# @return [Boolean] Whether the element is visible
|
|
96
|
+
#
|
|
97
|
+
def visible?
|
|
98
|
+
native.xpath("./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or name()='script' or name()='head']").size == 0
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
##
|
|
102
|
+
#
|
|
103
|
+
# Whether or not the element is checked.
|
|
104
|
+
#
|
|
105
|
+
# @return [Boolean] Whether the element is checked
|
|
106
|
+
#
|
|
107
|
+
def checked?
|
|
108
|
+
native[:checked]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
##
|
|
112
|
+
#
|
|
113
|
+
# Whether or not the element is selected.
|
|
114
|
+
#
|
|
115
|
+
# @return [Boolean] Whether the element is selected
|
|
116
|
+
#
|
|
117
|
+
def selected?
|
|
118
|
+
native[:selected]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
protected
|
|
122
|
+
|
|
123
|
+
def find_in_base(selector, xpath)
|
|
124
|
+
native.xpath(xpath).map { |node| self.class.new(node) }
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def wait_until
|
|
128
|
+
yield # simple nodes don't need to wait
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module Capybara
|
|
2
|
+
class Query
|
|
3
|
+
attr_accessor :selector, :locator, :options, :xpaths
|
|
4
|
+
|
|
5
|
+
def initialize(*args)
|
|
6
|
+
@options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
|
7
|
+
unless options.has_key?(:visible)
|
|
8
|
+
@options[:visible] = Capybara.ignore_hidden_elements
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
if args[1]
|
|
12
|
+
@selector = Selector.all[args[0]]
|
|
13
|
+
@locator = args[1]
|
|
14
|
+
else
|
|
15
|
+
@selector = Selector.all.values.find { |s| s.match?(args[0]) }
|
|
16
|
+
@locator = args[0]
|
|
17
|
+
end
|
|
18
|
+
@selector ||= Selector.all[Capybara.default_selector]
|
|
19
|
+
|
|
20
|
+
xpath = @selector.call(@locator)
|
|
21
|
+
if xpath.respond_to?(:to_xpaths)
|
|
22
|
+
@xpaths = xpath.to_xpaths
|
|
23
|
+
else
|
|
24
|
+
@xpaths = [xpath.to_s].flatten
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def failure_message(type, node)
|
|
29
|
+
message = selector.failure_message.call(node, self) if selector.failure_message
|
|
30
|
+
message ||= options[:message]
|
|
31
|
+
if type == :assert
|
|
32
|
+
message ||= "expected #{description} to return something"
|
|
33
|
+
else
|
|
34
|
+
message ||= "Unable to find #{description}"
|
|
35
|
+
end
|
|
36
|
+
message
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def negative_failure_message(type, node)
|
|
40
|
+
"expected #{description} not to return anything"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def name; selector.name; end
|
|
44
|
+
|
|
45
|
+
def description
|
|
46
|
+
@description = "#{name} #{locator.inspect}"
|
|
47
|
+
@description << " with text #{options[:text].inspect}" if options[:text]
|
|
48
|
+
@description
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def matches_filters?(node)
|
|
52
|
+
if options[:text]
|
|
53
|
+
regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text])
|
|
54
|
+
return false if not node.text.match(regexp)
|
|
55
|
+
end
|
|
56
|
+
return false if options[:visible] and not node.visible?
|
|
57
|
+
selector.custom_filters.each do |name, block|
|
|
58
|
+
return false if options.has_key?(name) and not block.call(node, options[name])
|
|
59
|
+
end
|
|
60
|
+
true
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
class Capybara::RackTest::Browser
|
|
2
|
+
include ::Rack::Test::Methods
|
|
3
|
+
|
|
4
|
+
attr_reader :driver
|
|
5
|
+
attr_accessor :current_host
|
|
6
|
+
|
|
7
|
+
def initialize(driver)
|
|
8
|
+
@driver = driver
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def app
|
|
12
|
+
driver.app
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def options
|
|
16
|
+
driver.options
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def visit(path, attributes = {})
|
|
20
|
+
reset_host!
|
|
21
|
+
process(:get, path, attributes)
|
|
22
|
+
follow_redirects!
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def submit(method, path, attributes)
|
|
26
|
+
path = request_path if not path or path.empty?
|
|
27
|
+
process(method, path, attributes)
|
|
28
|
+
follow_redirects!
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def follow(method, path, attributes = {})
|
|
32
|
+
return if path.gsub(/^#{request_path}/, '').start_with?('#')
|
|
33
|
+
process(method, path, attributes)
|
|
34
|
+
follow_redirects!
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def follow_redirects!
|
|
38
|
+
5.times do
|
|
39
|
+
process(:get, last_response["Location"]) if last_response.redirect?
|
|
40
|
+
end
|
|
41
|
+
raise Capybara::InfiniteRedirectError, "redirected more than 5 times, check for infinite redirects." if last_response.redirect?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def process(method, path, attributes = {})
|
|
45
|
+
new_uri = URI.parse(path)
|
|
46
|
+
method.downcase! unless method.is_a? Symbol
|
|
47
|
+
|
|
48
|
+
if new_uri.host
|
|
49
|
+
@current_host = "#{new_uri.scheme}://#{new_uri.host}"
|
|
50
|
+
@current_host << ":#{new_uri.port}" if new_uri.port != new_uri.default_port
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if new_uri.relative?
|
|
54
|
+
if path.start_with?('?')
|
|
55
|
+
path = request_path + path
|
|
56
|
+
elsif not path.start_with?('/')
|
|
57
|
+
path = request_path.sub(%r(/[^/]*$), '/') + path
|
|
58
|
+
end
|
|
59
|
+
path = current_host + path
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
reset_cache!
|
|
63
|
+
send(method, path, attributes, env)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def current_url
|
|
67
|
+
last_request.url
|
|
68
|
+
rescue Rack::Test::Error
|
|
69
|
+
""
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def reset_host!
|
|
73
|
+
@current_host = (Capybara.app_host || Capybara.default_host)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def reset_cache!
|
|
77
|
+
@dom = nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def body
|
|
81
|
+
dom.to_xml
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def dom
|
|
85
|
+
@dom ||= Nokogiri::HTML(source)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def find(selector)
|
|
89
|
+
dom.xpath(selector).map { |node| Capybara::RackTest::Node.new(self, node) }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def source
|
|
93
|
+
last_response.body
|
|
94
|
+
rescue Rack::Test::Error
|
|
95
|
+
""
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
protected
|
|
99
|
+
|
|
100
|
+
def build_rack_mock_session
|
|
101
|
+
reset_host! unless current_host
|
|
102
|
+
Rack::MockSession.new(app, URI.parse(current_host).host)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def request_path
|
|
106
|
+
last_request.path
|
|
107
|
+
rescue Rack::Test::Error
|
|
108
|
+
""
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def env
|
|
112
|
+
env = {}
|
|
113
|
+
begin
|
|
114
|
+
if last_response.redirect?
|
|
115
|
+
env["HTTP_REFERER"] = last_request.env["HTTP_REFERER"]
|
|
116
|
+
else
|
|
117
|
+
env["HTTP_REFERER"] = last_request.url
|
|
118
|
+
end
|
|
119
|
+
rescue Rack::Test::Error
|
|
120
|
+
# no request yet
|
|
121
|
+
end
|
|
122
|
+
env.merge!(options[:headers]) if options[:headers]
|
|
123
|
+
env
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'rack/test'
|
|
2
|
+
require 'rack/utils'
|
|
3
|
+
require 'mime/types'
|
|
4
|
+
require 'nokogiri'
|
|
5
|
+
require 'cgi'
|
|
6
|
+
|
|
7
|
+
class Capybara::RackTest::Driver < Capybara::Driver::Base
|
|
8
|
+
DEFAULT_OPTIONS = {
|
|
9
|
+
:respect_data_method => true
|
|
10
|
+
}
|
|
11
|
+
attr_reader :app, :options
|
|
12
|
+
|
|
13
|
+
def initialize(app, options={})
|
|
14
|
+
raise ArgumentError, "rack-test requires a rack application, but none was given" unless app
|
|
15
|
+
@app = app
|
|
16
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def browser
|
|
20
|
+
@browser ||= Capybara::RackTest::Browser.new(self)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def response
|
|
24
|
+
browser.last_response
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def request
|
|
28
|
+
browser.last_request
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def visit(path, attributes = {})
|
|
32
|
+
browser.visit(path, attributes)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def submit(method, path, attributes)
|
|
36
|
+
browser.submit(method, path, attributes)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def follow(method, path, attributes = {})
|
|
40
|
+
browser.follow(method, path, attributes)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def current_url
|
|
44
|
+
browser.current_url
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def response_headers
|
|
48
|
+
response.headers
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def status_code
|
|
52
|
+
response.status
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def find(selector)
|
|
56
|
+
browser.find(selector)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def body
|
|
60
|
+
browser.body
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def source
|
|
64
|
+
browser.source
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def dom
|
|
68
|
+
browser.dom
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def reset!
|
|
72
|
+
@browser = nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def get(*args, &block); browser.get(*args, &block); end
|
|
76
|
+
def post(*args, &block); browser.post(*args, &block); end
|
|
77
|
+
def put(*args, &block); browser.put(*args, &block); end
|
|
78
|
+
def delete(*args, &block); browser.delete(*args, &block); end
|
|
79
|
+
def header(key, value); browser.header(key, value); end
|
|
80
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
class Capybara::RackTest::Form < Capybara::RackTest::Node
|
|
2
|
+
# This only needs to inherit from Rack::Test::UploadedFile because Rack::Test checks for
|
|
3
|
+
# the class specifically when determing whether to consturct the request as multipart.
|
|
4
|
+
# That check should be based solely on the form element's 'enctype' attribute value,
|
|
5
|
+
# which should probably be provided to Rack::Test in its non-GET request methods.
|
|
6
|
+
class NilUploadedFile < Rack::Test::UploadedFile
|
|
7
|
+
def initialize
|
|
8
|
+
@empty_file = Tempfile.new("nil_uploaded_file")
|
|
9
|
+
@empty_file.close
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def original_filename; ""; end
|
|
13
|
+
def content_type; "application/octet-stream"; end
|
|
14
|
+
def path; @empty_file.path; end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def params(button)
|
|
18
|
+
params = {}
|
|
19
|
+
|
|
20
|
+
native.xpath("(.//input|.//select|.//textarea)[not(@disabled)]").map do |field|
|
|
21
|
+
case field.name
|
|
22
|
+
when 'input'
|
|
23
|
+
if %w(radio checkbox).include? field['type']
|
|
24
|
+
merge_param!(params, field['name'].to_s, field['value'].to_s) if field['checked']
|
|
25
|
+
elsif %w(submit image).include? field['type']
|
|
26
|
+
# TO DO identify the click button here (in document order, rather
|
|
27
|
+
# than leaving until the end of the params)
|
|
28
|
+
elsif field['type'] =='file'
|
|
29
|
+
if multipart?
|
|
30
|
+
file = \
|
|
31
|
+
if (value = field['value']).to_s.empty?
|
|
32
|
+
NilUploadedFile.new
|
|
33
|
+
else
|
|
34
|
+
content_type = MIME::Types.type_for(value).first.to_s
|
|
35
|
+
Rack::Test::UploadedFile.new(value, content_type)
|
|
36
|
+
end
|
|
37
|
+
merge_param!(params, field['name'].to_s, file)
|
|
38
|
+
else
|
|
39
|
+
merge_param!(params, field['name'].to_s, File.basename(field['value'].to_s))
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
merge_param!(params, field['name'].to_s, field['value'].to_s)
|
|
43
|
+
end
|
|
44
|
+
when 'select'
|
|
45
|
+
if field['multiple'] == 'multiple'
|
|
46
|
+
options = field.xpath(".//option[@selected]")
|
|
47
|
+
options.each do |option|
|
|
48
|
+
merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s)
|
|
49
|
+
end
|
|
50
|
+
else
|
|
51
|
+
option = field.xpath(".//option[@selected]").first
|
|
52
|
+
option ||= field.xpath('.//option').first
|
|
53
|
+
merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s) if option
|
|
54
|
+
end
|
|
55
|
+
when 'textarea'
|
|
56
|
+
merge_param!(params, field['name'].to_s, field.text.to_s)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
merge_param!(params, button[:name], button[:value] || "") if button[:name]
|
|
60
|
+
params
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def submit(button)
|
|
64
|
+
driver.submit(method, native['action'].to_s, params(button))
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def multipart?
|
|
68
|
+
self[:enctype] == "multipart/form-data"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def method
|
|
74
|
+
self[:method] =~ /post/i ? :post : :get
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def merge_param!(params, key, value)
|
|
78
|
+
Rack::Utils.normalize_params(params, key, value)
|
|
79
|
+
end
|
|
80
|
+
end
|