capybara 2.18.0 → 3.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.
- checksums.yaml +4 -4
- data/History.md +55 -1
- data/README.md +18 -17
- data/lib/capybara/config.rb +11 -58
- data/lib/capybara/cucumber.rb +2 -3
- data/lib/capybara/driver/base.rb +15 -16
- data/lib/capybara/driver/node.rb +5 -4
- data/lib/capybara/dsl.rb +1 -0
- data/lib/capybara/helpers.rb +19 -29
- data/lib/capybara/minitest/spec.rb +15 -14
- data/lib/capybara/minitest.rb +139 -138
- data/lib/capybara/node/actions.rb +60 -81
- data/lib/capybara/node/base.rb +11 -18
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +8 -8
- data/lib/capybara/node/element.rb +30 -40
- data/lib/capybara/node/finders.rb +62 -70
- data/lib/capybara/node/matchers.rb +50 -71
- data/lib/capybara/node/simple.rb +11 -17
- data/lib/capybara/queries/ancestor_query.rb +11 -7
- data/lib/capybara/queries/base_query.rb +22 -18
- data/lib/capybara/queries/current_path_query.rb +8 -24
- data/lib/capybara/queries/match_query.rb +3 -7
- data/lib/capybara/queries/selector_query.rb +92 -95
- data/lib/capybara/queries/sibling_query.rb +4 -4
- data/lib/capybara/queries/text_query.rb +35 -35
- data/lib/capybara/queries/title_query.rb +8 -11
- data/lib/capybara/rack_test/browser.rb +15 -18
- data/lib/capybara/rack_test/css_handlers.rb +6 -4
- data/lib/capybara/rack_test/driver.rb +6 -10
- data/lib/capybara/rack_test/form.rb +50 -40
- data/lib/capybara/rack_test/node.rb +93 -63
- data/lib/capybara/rails.rb +2 -6
- data/lib/capybara/result.rb +22 -22
- data/lib/capybara/rspec/compound.rb +5 -10
- data/lib/capybara/rspec/features.rb +17 -48
- data/lib/capybara/rspec/matcher_proxies.rb +31 -15
- data/lib/capybara/rspec/matchers.rb +70 -61
- data/lib/capybara/rspec.rb +5 -10
- data/lib/capybara/selector/css.rb +6 -11
- data/lib/capybara/selector/filter.rb +1 -17
- data/lib/capybara/selector/filter_set.rb +18 -15
- data/lib/capybara/selector/filters/base.rb +7 -6
- data/lib/capybara/selector/filters/expression_filter.rb +6 -23
- data/lib/capybara/selector/filters/node_filter.rb +2 -12
- data/lib/capybara/selector/selector.rb +28 -34
- data/lib/capybara/selector.rb +129 -117
- data/lib/capybara/selenium/driver.rb +131 -125
- data/lib/capybara/selenium/node.rb +197 -115
- data/lib/capybara/server.rb +3 -2
- data/lib/capybara/session/config.rb +47 -67
- data/lib/capybara/session/matchers.rb +8 -7
- data/lib/capybara/session.rb +138 -224
- data/lib/capybara/spec/public/test.js +25 -4
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -0
- data/lib/capybara/spec/session/accept_confirm_spec.rb +3 -2
- data/lib/capybara/spec/session/accept_prompt_spec.rb +1 -0
- data/lib/capybara/spec/session/all_spec.rb +31 -18
- data/lib/capybara/spec/session/ancestor_spec.rb +6 -8
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +6 -5
- data/lib/capybara/spec/session/assert_current_path.rb +12 -11
- data/lib/capybara/spec/session/assert_selector.rb +1 -0
- data/lib/capybara/spec/session/assert_text.rb +23 -23
- data/lib/capybara/spec/session/assert_title.rb +13 -3
- data/lib/capybara/spec/session/attach_file_spec.rb +51 -30
- data/lib/capybara/spec/session/body_spec.rb +1 -0
- data/lib/capybara/spec/session/check_spec.rb +7 -6
- data/lib/capybara/spec/session/choose_spec.rb +5 -4
- data/lib/capybara/spec/session/click_button_spec.rb +24 -32
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +8 -7
- data/lib/capybara/spec/session/click_link_spec.rb +8 -7
- data/lib/capybara/spec/session/current_scope_spec.rb +4 -3
- data/lib/capybara/spec/session/current_url_spec.rb +17 -6
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +1 -1
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +1 -0
- data/lib/capybara/spec/session/element/assert_match_selector.rb +1 -1
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +1 -1
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +5 -5
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +3 -2
- data/lib/capybara/spec/session/evaluate_script_spec.rb +4 -3
- data/lib/capybara/spec/session/execute_script_spec.rb +4 -3
- data/lib/capybara/spec/session/fill_in_spec.rb +30 -5
- data/lib/capybara/spec/session/find_button_spec.rb +4 -3
- data/lib/capybara/spec/session/find_by_id_spec.rb +2 -1
- data/lib/capybara/spec/session/find_field_spec.rb +9 -15
- data/lib/capybara/spec/session/find_link_spec.rb +6 -5
- data/lib/capybara/spec/session/find_spec.rb +37 -31
- data/lib/capybara/spec/session/first_spec.rb +60 -33
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +23 -0
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +2 -1
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +9 -16
- data/lib/capybara/spec/session/go_back_spec.rb +1 -0
- data/lib/capybara/spec/session/go_forward_spec.rb +1 -0
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +15 -15
- data/lib/capybara/spec/session/has_button_spec.rb +2 -1
- data/lib/capybara/spec/session/has_css_spec.rb +3 -2
- data/lib/capybara/spec/session/has_current_path_spec.rb +12 -28
- data/lib/capybara/spec/session/has_field_spec.rb +4 -3
- data/lib/capybara/spec/session/has_link_spec.rb +1 -0
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +17 -17
- data/lib/capybara/spec/session/has_select_spec.rb +30 -29
- data/lib/capybara/spec/session/has_selector_spec.rb +5 -4
- data/lib/capybara/spec/session/has_table_spec.rb +2 -1
- data/lib/capybara/spec/session/has_text_spec.rb +9 -13
- data/lib/capybara/spec/session/has_title_spec.rb +1 -0
- data/lib/capybara/spec/session/has_xpath_spec.rb +1 -0
- data/lib/capybara/spec/session/headers.rb +2 -1
- data/lib/capybara/spec/session/html_spec.rb +1 -0
- data/lib/capybara/spec/session/node_spec.rb +91 -56
- data/lib/capybara/spec/session/node_wrapper_spec.rb +36 -0
- data/lib/capybara/spec/session/refresh_spec.rb +6 -2
- data/lib/capybara/spec/session/reset_session_spec.rb +19 -0
- data/lib/capybara/spec/session/response_code.rb +1 -0
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -11
- data/lib/capybara/spec/session/save_page_spec.rb +1 -17
- data/lib/capybara/spec/session/save_screenshot_spec.rb +3 -3
- data/lib/capybara/spec/session/select_spec.rb +20 -20
- data/lib/capybara/spec/session/selectors_spec.rb +2 -2
- data/lib/capybara/spec/session/sibling_spec.rb +1 -1
- data/lib/capybara/spec/session/text_spec.rb +17 -3
- data/lib/capybara/spec/session/title_spec.rb +11 -1
- data/lib/capybara/spec/session/uncheck_spec.rb +4 -3
- data/lib/capybara/spec/session/unselect_spec.rb +6 -5
- data/lib/capybara/spec/session/visit_spec.rb +9 -3
- data/lib/capybara/spec/session/window/become_closed_spec.rb +2 -1
- data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +2 -1
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +2 -1
- data/lib/capybara/spec/session/window/window_spec.rb +12 -12
- data/lib/capybara/spec/session/window/windows_spec.rb +2 -3
- data/lib/capybara/spec/session/window/within_window_spec.rb +15 -71
- data/lib/capybara/spec/session/within_spec.rb +1 -0
- data/lib/capybara/spec/spec_helper.rb +34 -18
- data/lib/capybara/spec/test_app.rb +17 -9
- data/lib/capybara/spec/views/form.erb +7 -0
- data/lib/capybara/spec/views/with_html.erb +23 -1
- data/lib/capybara/spec/views/within_frames.erb +4 -1
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +6 -10
- data/lib/capybara.rb +28 -25
- data/spec/basic_node_spec.rb +1 -0
- data/spec/capybara_spec.rb +11 -50
- data/spec/dsl_spec.rb +5 -13
- data/spec/filter_set_spec.rb +5 -4
- data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +3 -2
- data/spec/minitest_spec.rb +4 -3
- data/spec/minitest_spec_spec.rb +3 -2
- data/spec/per_session_config_spec.rb +9 -8
- data/spec/rack_test_spec.rb +21 -20
- data/spec/result_spec.rb +17 -16
- data/spec/rspec/features_spec.rb +17 -14
- data/spec/rspec/scenarios_spec.rb +5 -7
- data/spec/rspec/shared_spec_matchers.rb +96 -99
- data/spec/rspec/views_spec.rb +2 -1
- data/spec/rspec_matchers_spec.rb +18 -2
- data/spec/rspec_spec.rb +11 -15
- data/spec/selector_spec.rb +5 -6
- data/spec/selenium_spec_chrome.rb +9 -4
- data/spec/selenium_spec_edge.rb +27 -0
- data/spec/selenium_spec_ie.rb +31 -0
- data/spec/selenium_spec_marionette.rb +28 -12
- data/spec/server_spec.rb +33 -33
- data/spec/session_spec.rb +2 -1
- data/spec/shared_selenium_session.rb +36 -22
- data/spec/spec_helper.rb +3 -6
- metadata +68 -85
- data/lib/capybara/query.rb +0 -7
- data/spec/selenium_spec_firefox.rb +0 -68
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
class Capybara::RackTest::Form < Capybara::RackTest::Node
|
3
4
|
# This only needs to inherit from Rack::Test::UploadedFile because Rack::Test checks for
|
4
5
|
# the class specifically when determining whether to construct the request as multipart.
|
@@ -20,53 +21,21 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
|
|
20
21
|
def params(button)
|
21
22
|
params = make_params
|
22
23
|
|
23
|
-
form_element_types=[
|
24
|
-
form_elements_xpath=XPath.generate do |x|
|
25
|
-
xpath=x.descendant(*form_element_types).where(
|
26
|
-
xpath
|
27
|
-
xpath.where(
|
24
|
+
form_element_types = %i[input select textarea]
|
25
|
+
form_elements_xpath = XPath.generate do |x|
|
26
|
+
xpath = x.descendant(*form_element_types).where(!x.attr(:form))
|
27
|
+
xpath += x.anywhere(*form_element_types).where(x.attr(:form) == native[:id]) if native[:id]
|
28
|
+
xpath.where(!x.attr(:disabled))
|
28
29
|
end.to_s
|
29
30
|
|
30
31
|
native.xpath(form_elements_xpath).map do |field|
|
31
32
|
case field.name
|
32
33
|
when 'input'
|
33
|
-
|
34
|
-
if field['checked']
|
35
|
-
node=Capybara::RackTest::Node.new(self.driver, field)
|
36
|
-
merge_param!(params, field['name'].to_s, node.value.to_s)
|
37
|
-
end
|
38
|
-
elsif %w(submit image).include? field['type']
|
39
|
-
# TO DO identify the click button here (in document order, rather
|
40
|
-
# than leaving until the end of the params)
|
41
|
-
elsif field['type'] =='file'
|
42
|
-
if multipart?
|
43
|
-
file = \
|
44
|
-
if (value = field['value']).to_s.empty?
|
45
|
-
NilUploadedFile.new
|
46
|
-
else
|
47
|
-
mime_info = MiniMime.lookup_by_filename(value)
|
48
|
-
Rack::Test::UploadedFile.new(value, (mime_info && mime_info.content_type).to_s)
|
49
|
-
end
|
50
|
-
merge_param!(params, field['name'].to_s, file)
|
51
|
-
else
|
52
|
-
merge_param!(params, field['name'].to_s, File.basename(field['value'].to_s))
|
53
|
-
end
|
54
|
-
else
|
55
|
-
merge_param!(params, field['name'].to_s, field['value'].to_s)
|
56
|
-
end
|
34
|
+
add_input_param(field, params)
|
57
35
|
when 'select'
|
58
|
-
|
59
|
-
options = field.xpath(".//option[@selected]")
|
60
|
-
options.each do |option|
|
61
|
-
merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s)
|
62
|
-
end
|
63
|
-
else
|
64
|
-
option = field.xpath(".//option[@selected]").first
|
65
|
-
option ||= field.xpath('.//option').first
|
66
|
-
merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s) if option
|
67
|
-
end
|
36
|
+
add_select_param(field, params)
|
68
37
|
when 'textarea'
|
69
|
-
|
38
|
+
add_textarea_param(field, params)
|
70
39
|
end
|
71
40
|
end
|
72
41
|
merge_param!(params, button[:name], button[:value] || "") if button[:name]
|
@@ -111,4 +80,45 @@ private
|
|
111
80
|
ParamsHash.new
|
112
81
|
end
|
113
82
|
end
|
83
|
+
|
84
|
+
def add_input_param(field, params)
|
85
|
+
if %w[radio checkbox].include? field['type']
|
86
|
+
if field['checked']
|
87
|
+
node = Capybara::RackTest::Node.new(driver, field)
|
88
|
+
merge_param!(params, field['name'].to_s, node.value.to_s)
|
89
|
+
end
|
90
|
+
elsif %w[submit image].include? field['type']
|
91
|
+
# TODO: identify the click button here (in document order, rather
|
92
|
+
# than leaving until the end of the params)
|
93
|
+
elsif field['type'] == 'file'
|
94
|
+
if multipart?
|
95
|
+
file = if (value = field['value']).to_s.empty?
|
96
|
+
NilUploadedFile.new
|
97
|
+
else
|
98
|
+
mime_info = MiniMime.lookup_by_filename(value)
|
99
|
+
Rack::Test::UploadedFile.new(value, (mime_info && mime_info.content_type).to_s)
|
100
|
+
end
|
101
|
+
merge_param!(params, field['name'].to_s, file)
|
102
|
+
else
|
103
|
+
merge_param!(params, field['name'].to_s, File.basename(field['value'].to_s))
|
104
|
+
end
|
105
|
+
else
|
106
|
+
merge_param!(params, field['name'].to_s, field['value'].to_s)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def add_select_param(field, params)
|
111
|
+
if field['multiple'] == 'multiple'
|
112
|
+
field.xpath(".//option[@selected]").each do |option|
|
113
|
+
merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s)
|
114
|
+
end
|
115
|
+
else
|
116
|
+
option = field.xpath('.//option[@selected]').first || field.xpath('.//option').first
|
117
|
+
merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s) if option
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def add_textarea_param(field, params)
|
122
|
+
merge_param!(params, field['name'].to_s, field['_capybara_raw_value'].to_s.gsub(/\n/, "\r\n"))
|
123
|
+
end
|
114
124
|
end
|
@@ -1,11 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
class Capybara::RackTest::Node < Capybara::Driver::Node
|
4
|
+
BLOCK_ELEMENTS = %w[p h1 h2 h3 h4 h5 h6 ol ul pre address blockquote dl div fieldset form hr noscript table].freeze
|
5
|
+
|
3
6
|
def all_text
|
4
|
-
|
7
|
+
native.text
|
8
|
+
.gsub(/[\u200b\u200e\u200f]/, '')
|
9
|
+
.gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
|
10
|
+
.gsub(/\A[[:space:]&&[^\u00a0]]+/, "")
|
11
|
+
.gsub(/[[:space:]&&[^\u00a0]]+\z/, "")
|
12
|
+
.tr("\u00a0", ' ')
|
5
13
|
end
|
6
14
|
|
7
15
|
def visible_text
|
8
|
-
|
16
|
+
displayed_text.gsub(/\ +/, ' ')
|
17
|
+
.gsub(/[\ \n]*\n[\ \n]*/, "\n")
|
18
|
+
.gsub(/\A[[:space:]&&[^\u00a0]]+/, "")
|
19
|
+
.gsub(/[[:space:]&&[^\u00a0]]+\z/, "")
|
20
|
+
.tr("\u00a0", ' ')
|
9
21
|
end
|
10
22
|
|
11
23
|
def [](name)
|
@@ -16,64 +28,45 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
16
28
|
string_node.value
|
17
29
|
end
|
18
30
|
|
19
|
-
def set(value)
|
20
|
-
return if disabled?
|
21
|
-
if readonly?
|
22
|
-
warn "Attempt to set readonly element with value: #{value} \n * This will raise an exception in a future version of Capybara"
|
23
|
-
return
|
24
|
-
end
|
31
|
+
def set(value, **options)
|
32
|
+
return if disabled? || readonly?
|
25
33
|
|
26
|
-
|
27
|
-
|
34
|
+
warn "Options passed to Node#set but the RackTest driver doesn't support any - ignoring" unless options.empty?
|
35
|
+
|
36
|
+
if value.is_a?(Array) && !multiple?
|
37
|
+
raise TypeError, "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
|
28
38
|
end
|
29
39
|
|
30
|
-
if radio?
|
31
|
-
|
32
|
-
elsif
|
33
|
-
|
34
|
-
elsif input_field?
|
35
|
-
set_input(value)
|
36
|
-
elsif textarea?
|
37
|
-
native['_capybara_raw_value'] = value.to_s
|
40
|
+
if radio? then set_radio(value)
|
41
|
+
elsif checkbox? then set_checkbox(value)
|
42
|
+
elsif input_field? then set_input(value)
|
43
|
+
elsif textarea? then native['_capybara_raw_value'] = value.to_s
|
38
44
|
end
|
39
45
|
end
|
40
46
|
|
41
47
|
def select_option
|
42
48
|
return if disabled?
|
43
|
-
|
44
|
-
select_node.find_xpath(".//option[@selected]").each { |node| node.native.remove_attribute("selected") }
|
45
|
-
end
|
49
|
+
deselect_options unless select_node.multiple?
|
46
50
|
native["selected"] = 'selected'
|
47
51
|
end
|
48
52
|
|
49
53
|
def unselect_option
|
50
|
-
|
51
|
-
raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box."
|
52
|
-
end
|
54
|
+
raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box." unless select_node.multiple?
|
53
55
|
native.remove_attribute('selected')
|
54
56
|
end
|
55
57
|
|
56
|
-
def click
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
elsif
|
62
|
-
((tag_name == 'button') and type.nil? or type == "submit")
|
58
|
+
def click(keys = [], offset = {})
|
59
|
+
raise ArgumentError, "The RackTest driver does not support click options" unless keys.empty? && offset.empty?
|
60
|
+
|
61
|
+
if link?
|
62
|
+
follow_link
|
63
|
+
elsif submits?
|
63
64
|
associated_form = form
|
64
65
|
Capybara::RackTest::Form.new(driver, associated_form).submit(self) if associated_form
|
65
|
-
elsif
|
66
|
+
elsif checkable?
|
66
67
|
set(!checked?)
|
67
|
-
elsif
|
68
|
-
|
69
|
-
find_xpath("//input[@id='#{native[:for]}']").first
|
70
|
-
else
|
71
|
-
find_xpath(".//input").first
|
72
|
-
end
|
73
|
-
|
74
|
-
if labelled_control && (labelled_control.checkbox? || labelled_control.radio?)
|
75
|
-
labelled_control.set(!labelled_control.checked?)
|
76
|
-
end
|
68
|
+
elsif tag_name == 'label'
|
69
|
+
click_label
|
77
70
|
end
|
78
71
|
end
|
79
72
|
|
@@ -94,10 +87,12 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
94
87
|
end
|
95
88
|
|
96
89
|
def disabled?
|
97
|
-
if
|
98
|
-
|
90
|
+
return true if string_node.disabled?
|
91
|
+
|
92
|
+
if %w[option optgroup].include? tag_name
|
93
|
+
find_xpath("parent::*[self::optgroup or self::select]")[0].disabled?
|
99
94
|
else
|
100
|
-
|
95
|
+
!find_xpath("parent::fieldset[@disabled] | ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]").empty?
|
101
96
|
end
|
102
97
|
end
|
103
98
|
|
@@ -119,15 +114,20 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
119
114
|
|
120
115
|
protected
|
121
116
|
|
122
|
-
|
123
|
-
|
117
|
+
# @api private
|
118
|
+
def displayed_text(check_ancestor: true)
|
119
|
+
if !string_node.visible?(check_ancestor)
|
124
120
|
''
|
125
121
|
elsif native.text?
|
126
122
|
native.text
|
123
|
+
.gsub(/[\u200b\u200e\u200f]/, '')
|
124
|
+
.gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
|
127
125
|
elsif native.element?
|
128
|
-
native.children.map do |child|
|
129
|
-
Capybara::RackTest::Node.new(driver, child).
|
130
|
-
end.join
|
126
|
+
text = native.children.map do |child|
|
127
|
+
Capybara::RackTest::Node.new(driver, child).displayed_text(check_ancestor: false)
|
128
|
+
end.join || ''
|
129
|
+
text = "\n#{text}\n" if BLOCK_ELEMENTS.include?(tag_name)
|
130
|
+
text
|
131
131
|
else
|
132
132
|
''
|
133
133
|
end
|
@@ -135,6 +135,10 @@ protected
|
|
135
135
|
|
136
136
|
private
|
137
137
|
|
138
|
+
def deselect_options
|
139
|
+
select_node.find_xpath(".//option[@selected]").each { |node| node.native.remove_attribute("selected") }
|
140
|
+
end
|
141
|
+
|
138
142
|
def string_node
|
139
143
|
@string_node ||= Capybara::Node::Simple.new(native)
|
140
144
|
end
|
@@ -150,19 +154,19 @@ private
|
|
150
154
|
|
151
155
|
def form
|
152
156
|
if native[:form]
|
153
|
-
native.xpath("//form[@id='#{native[:form]}']")
|
157
|
+
native.xpath("//form[@id='#{native[:form]}']")
|
154
158
|
else
|
155
|
-
native.ancestors('form')
|
156
|
-
end
|
159
|
+
native.ancestors('form')
|
160
|
+
end.first
|
157
161
|
end
|
158
162
|
|
159
|
-
def set_radio(_value)
|
160
|
-
other_radios_xpath = XPath.generate { |x| x.anywhere(:input)[x.attr(:name)
|
163
|
+
def set_radio(_value) # rubocop:disable Naming/AccessorMethodName
|
164
|
+
other_radios_xpath = XPath.generate { |x| x.anywhere(:input)[x.attr(:name) == self[:name]] }.to_s
|
161
165
|
driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute("checked") }
|
162
166
|
native['checked'] = 'checked'
|
163
167
|
end
|
164
168
|
|
165
|
-
def set_checkbox(value)
|
169
|
+
def set_checkbox(value) # rubocop:disable Naming/AccessorMethodName
|
166
170
|
if value && !native['checked']
|
167
171
|
native['checked'] = 'checked'
|
168
172
|
elsif !value && native['checked']
|
@@ -170,13 +174,13 @@ private
|
|
170
174
|
end
|
171
175
|
end
|
172
176
|
|
173
|
-
def set_input(value)
|
177
|
+
def set_input(value) # rubocop:disable Naming/AccessorMethodName
|
174
178
|
if text_or_password? && attribute_is_not_blank?(:maxlength)
|
175
179
|
# Browser behavior for maxlength="0" is inconsistent, so we stick with
|
176
180
|
# Firefox, allowing no input
|
177
181
|
value = value.to_s[0...self[:maxlength].to_i]
|
178
182
|
end
|
179
|
-
if Array
|
183
|
+
if value.is_a?(Array) # Assert multiple attribute is present
|
180
184
|
value.each do |v|
|
181
185
|
new_native = native.clone
|
182
186
|
new_native.remove_attribute('value')
|
@@ -185,11 +189,7 @@ private
|
|
185
189
|
end
|
186
190
|
native.remove
|
187
191
|
else
|
188
|
-
|
189
|
-
warn "Attempt to set readonly element with value: #{value} \n *This will raise an exception in a future version of Capybara"
|
190
|
-
else
|
191
|
-
native['value'] = value.to_s
|
192
|
-
end
|
192
|
+
native['value'] = value.to_s
|
193
193
|
end
|
194
194
|
end
|
195
195
|
|
@@ -197,6 +197,36 @@ private
|
|
197
197
|
self[attribute] && !self[attribute].empty?
|
198
198
|
end
|
199
199
|
|
200
|
+
def follow_link
|
201
|
+
method = self["data-method"] if driver.options[:respect_data_method]
|
202
|
+
method ||= :get
|
203
|
+
driver.follow(method, self[:href].to_s)
|
204
|
+
end
|
205
|
+
|
206
|
+
def click_label
|
207
|
+
labelled_control = if native[:for]
|
208
|
+
find_xpath("//input[@id='#{native[:for]}']")
|
209
|
+
else
|
210
|
+
find_xpath(".//input")
|
211
|
+
end.first
|
212
|
+
|
213
|
+
if labelled_control && (labelled_control.checkbox? || labelled_control.radio?)
|
214
|
+
labelled_control.set(!labelled_control.checked?)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def link?
|
219
|
+
tag_name == 'a' && !self[:href].nil?
|
220
|
+
end
|
221
|
+
|
222
|
+
def submits?
|
223
|
+
(tag_name == 'input' and %w[submit image].include?(type)) || (tag_name == 'button' and [nil, "submit"].include?(type))
|
224
|
+
end
|
225
|
+
|
226
|
+
def checkable?
|
227
|
+
tag_name == 'input' and %w[checkbox radio].include?(type)
|
228
|
+
end
|
229
|
+
|
200
230
|
protected
|
201
231
|
|
202
232
|
def checkbox?
|
data/lib/capybara/rails.rb
CHANGED
@@ -1,14 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'capybara/dsl'
|
3
4
|
|
4
5
|
Capybara.app = Rack::Builder.new do
|
5
6
|
map "/" do
|
6
|
-
|
7
|
-
run Rails.application
|
8
|
-
else # Rails 2
|
9
|
-
use Rails::Rack::Static
|
10
|
-
run ActionController::Dispatcher.new
|
11
|
-
end
|
7
|
+
run Rails.application
|
12
8
|
end
|
13
9
|
end.to_app
|
14
10
|
|
data/lib/capybara/result.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'forwardable'
|
3
4
|
|
4
5
|
module Capybara
|
5
|
-
|
6
6
|
##
|
7
7
|
# A {Capybara::Result} represents a collection of {Capybara::Node::Element} on the page. It is possible to interact with this
|
8
8
|
# collection similar to an Array because it implements Enumerable and offers the following Array methods through delegation:
|
@@ -41,7 +41,7 @@ module Capybara
|
|
41
41
|
loop do
|
42
42
|
next_result = @results_enum.next
|
43
43
|
@result_cache << next_result
|
44
|
-
|
44
|
+
yield next_result
|
45
45
|
end
|
46
46
|
self
|
47
47
|
end
|
@@ -62,7 +62,7 @@ module Capybara
|
|
62
62
|
!any?
|
63
63
|
end
|
64
64
|
|
65
|
-
def
|
65
|
+
def compare_count
|
66
66
|
# Only check filters for as many elements as necessary to determine result
|
67
67
|
if @query.options[:count]
|
68
68
|
count_opt = Integer(@query.options[:count])
|
@@ -70,7 +70,7 @@ module Capybara
|
|
70
70
|
break if @result_cache.size > count_opt
|
71
71
|
@result_cache << @results_enum.next
|
72
72
|
end
|
73
|
-
return @result_cache.size
|
73
|
+
return @result_cache.size <=> count_opt
|
74
74
|
end
|
75
75
|
|
76
76
|
if @query.options[:minimum]
|
@@ -78,7 +78,7 @@ module Capybara
|
|
78
78
|
begin
|
79
79
|
@result_cache << @results_enum.next while @result_cache.size < min_opt
|
80
80
|
rescue StopIteration
|
81
|
-
return
|
81
|
+
return -1
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
@@ -86,32 +86,38 @@ module Capybara
|
|
86
86
|
max_opt = Integer(@query.options[:maximum])
|
87
87
|
begin
|
88
88
|
@result_cache << @results_enum.next while @result_cache.size <= max_opt
|
89
|
-
return
|
89
|
+
return 1
|
90
90
|
rescue StopIteration
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
94
|
if @query.options[:between]
|
95
|
-
max =
|
95
|
+
min, max = @query.options[:between].minmax
|
96
96
|
loop do
|
97
97
|
break if @result_cache.size > max
|
98
98
|
@result_cache << @results_enum.next
|
99
99
|
end
|
100
|
-
return
|
100
|
+
return 0 if @query.options[:between].include?(@result_cache.size)
|
101
|
+
return -1 if @result_cache.size < min
|
102
|
+
return 1
|
101
103
|
end
|
102
104
|
|
103
|
-
return
|
105
|
+
return 0
|
106
|
+
end
|
107
|
+
|
108
|
+
def matches_count?
|
109
|
+
compare_count.zero?
|
104
110
|
end
|
105
111
|
|
106
112
|
def failure_message
|
107
113
|
message = @query.failure_message
|
108
|
-
if count
|
109
|
-
message << ", found #{count} #{Capybara::Helpers.declension("match", "matches", count)}: " << full_results.map(&:text).map(&:inspect).join(", ")
|
110
|
-
else
|
114
|
+
if count.zero?
|
111
115
|
message << " but there were no matches"
|
116
|
+
else
|
117
|
+
message << ", found #{count} #{Capybara::Helpers.declension("match", "matches", count)}: " << full_results.map(&:text).map(&:inspect).join(", ")
|
112
118
|
end
|
113
119
|
unless rest.empty?
|
114
|
-
elements = rest.map
|
120
|
+
elements = rest.map { |el| el.text rescue "<<ERROR>>" }.map(&:inspect).join(", ")
|
115
121
|
message << ". Also found " << elements << ", which matched the selector but not all filters."
|
116
122
|
end
|
117
123
|
message
|
@@ -121,7 +127,7 @@ module Capybara
|
|
121
127
|
failure_message.sub(/(to find)/, 'not \1')
|
122
128
|
end
|
123
129
|
|
124
|
-
|
130
|
+
private
|
125
131
|
|
126
132
|
def full_results
|
127
133
|
loop { @result_cache << @results_enum.next }
|
@@ -137,15 +143,9 @@ module Capybara
|
|
137
143
|
# causes a concurrency issue with network requests here
|
138
144
|
# https://github.com/jruby/jruby/issues/4212
|
139
145
|
if RUBY_PLATFORM == 'java'
|
140
|
-
@elements.select(&block).to_enum
|
141
|
-
elsif @elements.respond_to? :lazy #Ruby 2.0+
|
142
|
-
@elements.lazy.select(&block)
|
146
|
+
@elements.select(&block).to_enum # non-lazy evaluation
|
143
147
|
else
|
144
|
-
|
145
|
-
@elements.each do |val|
|
146
|
-
yielder.yield(val) if block.call(val)
|
147
|
-
end
|
148
|
-
end
|
148
|
+
@elements.lazy.select(&block)
|
149
149
|
end
|
150
150
|
end
|
151
151
|
end
|
@@ -4,7 +4,7 @@ module Capybara
|
|
4
4
|
include ::RSpec::Matchers::Composable
|
5
5
|
|
6
6
|
def and(matcher)
|
7
|
-
Capybara::RSpecMatchers::Compound::And.new(self,matcher)
|
7
|
+
Capybara::RSpecMatchers::Compound::And.new(self, matcher)
|
8
8
|
end
|
9
9
|
|
10
10
|
def and_then(matcher)
|
@@ -15,12 +15,9 @@ module Capybara
|
|
15
15
|
Capybara::RSpecMatchers::Compound::Or.new(self, matcher)
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
18
|
class CapybaraEvaluator
|
20
|
-
def initialize(actual
|
21
|
-
@actual
|
22
|
-
@matcher_1 = matcher_1
|
23
|
-
@matcher_2 = matcher_2
|
19
|
+
def initialize(actual)
|
20
|
+
@actual = actual
|
24
21
|
@match_results = Hash.new { |h, matcher| h[matcher] = matcher.matches?(@actual) }
|
25
22
|
end
|
26
23
|
|
@@ -34,11 +31,10 @@ module Capybara
|
|
34
31
|
end
|
35
32
|
|
36
33
|
class And < ::RSpec::Matchers::BuiltIn::Compound::And
|
37
|
-
|
38
34
|
private
|
39
35
|
|
40
36
|
def match(_expected, actual)
|
41
|
-
@evaluator = CapybaraEvaluator.new(actual
|
37
|
+
@evaluator = CapybaraEvaluator.new(actual)
|
42
38
|
syncer = sync_element(actual)
|
43
39
|
begin
|
44
40
|
syncer.synchronize do
|
@@ -63,11 +59,10 @@ module Capybara
|
|
63
59
|
end
|
64
60
|
|
65
61
|
class Or < ::RSpec::Matchers::BuiltIn::Compound::Or
|
66
|
-
|
67
62
|
private
|
68
63
|
|
69
64
|
def match(_expected, actual)
|
70
|
-
@evaluator = CapybaraEvaluator.new(actual
|
65
|
+
@evaluator = CapybaraEvaluator.new(actual)
|
71
66
|
syncer = sync_element(actual)
|
72
67
|
begin
|
73
68
|
syncer.synchronize do
|
@@ -1,56 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
if RSpec::Core::Version::STRING.to_f >= 3.0
|
3
|
-
RSpec.shared_context "Capybara Features", capybara_feature: true do
|
4
|
-
instance_eval do
|
5
|
-
alias background before
|
6
|
-
alias given let
|
7
|
-
alias given! let!
|
8
|
-
end
|
9
|
-
end
|
10
2
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
3
|
+
RSpec.shared_context "Capybara Features", capybara_feature: true do
|
4
|
+
instance_eval do
|
5
|
+
alias background before
|
6
|
+
alias given let
|
7
|
+
alias given! let!
|
16
8
|
end
|
9
|
+
end
|
17
10
|
|
11
|
+
# ensure shared_context is included if default shared_context_metadata_behavior is changed
|
12
|
+
if RSpec::Core::Version::STRING.to_f >= 3.5
|
18
13
|
RSpec.configure do |config|
|
19
|
-
config.
|
20
|
-
config.alias_example_group_to :xfeature, capybara_feature: true, type: :feature, skip: "Temporarily disabled with xfeature"
|
21
|
-
config.alias_example_group_to :ffeature, capybara_feature: true, type: :feature, focus: true
|
22
|
-
config.alias_example_to :scenario
|
23
|
-
config.alias_example_to :xscenario, skip: "Temporarily disabled with xscenario"
|
24
|
-
config.alias_example_to :fscenario, focus: true
|
25
|
-
end
|
26
|
-
else
|
27
|
-
module Capybara
|
28
|
-
module Features
|
29
|
-
def self.included(base)
|
30
|
-
base.instance_eval do
|
31
|
-
alias :background :before
|
32
|
-
alias :scenario :it
|
33
|
-
alias :xscenario :xit
|
34
|
-
alias :given :let
|
35
|
-
alias :given! :let!
|
36
|
-
alias :feature :describe
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.feature(*args, &block)
|
43
|
-
options = if args.last.is_a?(Hash) then args.pop else {} end
|
44
|
-
options[:capybara_feature] = true
|
45
|
-
options[:type] = :feature
|
46
|
-
options[:caller] ||= caller
|
47
|
-
args.push(options)
|
48
|
-
|
49
|
-
#call describe on RSpec in case user has expose_dsl_globally set to false
|
50
|
-
RSpec.describe(*args, &block)
|
14
|
+
config.include_context "Capybara Features", capybara_feature: true
|
51
15
|
end
|
16
|
+
end
|
52
17
|
|
53
|
-
|
54
|
-
|
55
|
-
|
18
|
+
RSpec.configure do |config|
|
19
|
+
config.alias_example_group_to :feature, capybara_feature: true, type: :feature
|
20
|
+
config.alias_example_group_to :xfeature, capybara_feature: true, type: :feature, skip: "Temporarily disabled with xfeature"
|
21
|
+
config.alias_example_group_to :ffeature, capybara_feature: true, type: :feature, focus: true
|
22
|
+
config.alias_example_to :scenario
|
23
|
+
config.alias_example_to :xscenario, skip: "Temporarily disabled with xscenario"
|
24
|
+
config.alias_example_to :fscenario, focus: true
|
56
25
|
end
|