capybara 3.8.1 → 3.33.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/History.md +465 -0
- data/License.txt +1 -1
- data/README.md +58 -57
- data/lib/capybara/config.rb +10 -4
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +2 -2
- data/lib/capybara/driver/node.rb +26 -5
- data/lib/capybara/dsl.rb +12 -4
- data/lib/capybara/helpers.rb +8 -4
- data/lib/capybara/minitest/spec.rb +162 -85
- data/lib/capybara/minitest.rb +248 -148
- data/lib/capybara/node/actions.rb +149 -96
- data/lib/capybara/node/base.rb +27 -10
- data/lib/capybara/node/document.rb +12 -0
- data/lib/capybara/node/document_matchers.rb +9 -5
- data/lib/capybara/node/element.rb +254 -109
- data/lib/capybara/node/finders.rb +83 -76
- data/lib/capybara/node/matchers.rb +279 -141
- data/lib/capybara/node/simple.rb +25 -6
- data/lib/capybara/queries/ancestor_query.rb +5 -7
- data/lib/capybara/queries/base_query.rb +11 -5
- data/lib/capybara/queries/current_path_query.rb +3 -3
- data/lib/capybara/queries/match_query.rb +1 -0
- data/lib/capybara/queries/selector_query.rb +467 -103
- data/lib/capybara/queries/sibling_query.rb +5 -4
- data/lib/capybara/queries/style_query.rb +6 -2
- data/lib/capybara/queries/text_query.rb +17 -3
- data/lib/capybara/queries/title_query.rb +2 -2
- data/lib/capybara/rack_test/browser.rb +22 -15
- data/lib/capybara/rack_test/driver.rb +10 -1
- data/lib/capybara/rack_test/errors.rb +6 -0
- data/lib/capybara/rack_test/form.rb +33 -28
- data/lib/capybara/rack_test/node.rb +74 -6
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/drivers.rb +36 -0
- data/lib/capybara/registrations/patches/puma_ssl.rb +27 -0
- data/lib/capybara/registrations/servers.rb +44 -0
- data/lib/capybara/result.rb +55 -23
- data/lib/capybara/rspec/features.rb +4 -4
- data/lib/capybara/rspec/matcher_proxies.rb +36 -15
- data/lib/capybara/rspec/matchers/base.rb +111 -0
- data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
- data/lib/capybara/rspec/matchers/compound.rb +88 -0
- data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
- data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
- data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
- data/lib/capybara/rspec/matchers/have_selector.rb +77 -0
- data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
- data/lib/capybara/rspec/matchers/have_text.rb +33 -0
- data/lib/capybara/rspec/matchers/have_title.rb +29 -0
- data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
- data/lib/capybara/rspec/matchers/match_style.rb +38 -0
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/rspec/matchers.rb +117 -311
- data/lib/capybara/selector/builders/css_builder.rb +84 -0
- data/lib/capybara/selector/builders/xpath_builder.rb +69 -0
- data/lib/capybara/selector/css.rb +17 -15
- data/lib/capybara/selector/definition/button.rb +52 -0
- data/lib/capybara/selector/definition/checkbox.rb +26 -0
- data/lib/capybara/selector/definition/css.rb +10 -0
- data/lib/capybara/selector/definition/datalist_input.rb +35 -0
- data/lib/capybara/selector/definition/datalist_option.rb +25 -0
- data/lib/capybara/selector/definition/element.rb +27 -0
- data/lib/capybara/selector/definition/field.rb +40 -0
- data/lib/capybara/selector/definition/fieldset.rb +14 -0
- data/lib/capybara/selector/definition/file_field.rb +13 -0
- data/lib/capybara/selector/definition/fillable_field.rb +33 -0
- data/lib/capybara/selector/definition/frame.rb +17 -0
- data/lib/capybara/selector/definition/id.rb +6 -0
- data/lib/capybara/selector/definition/label.rb +62 -0
- data/lib/capybara/selector/definition/link.rb +54 -0
- data/lib/capybara/selector/definition/link_or_button.rb +16 -0
- data/lib/capybara/selector/definition/option.rb +27 -0
- data/lib/capybara/selector/definition/radio_button.rb +27 -0
- data/lib/capybara/selector/definition/select.rb +81 -0
- data/lib/capybara/selector/definition/table.rb +109 -0
- data/lib/capybara/selector/definition/table_row.rb +21 -0
- data/lib/capybara/selector/definition/xpath.rb +5 -0
- data/lib/capybara/selector/definition.rb +277 -0
- data/lib/capybara/selector/filter.rb +1 -0
- data/lib/capybara/selector/filter_set.rb +26 -19
- data/lib/capybara/selector/filters/base.rb +24 -5
- data/lib/capybara/selector/filters/expression_filter.rb +3 -3
- data/lib/capybara/selector/filters/locator_filter.rb +29 -0
- data/lib/capybara/selector/filters/node_filter.rb +16 -2
- data/lib/capybara/selector/regexp_disassembler.rb +214 -0
- data/lib/capybara/selector/selector.rb +73 -367
- data/lib/capybara/selector/xpath_extensions.rb +17 -0
- data/lib/capybara/selector.rb +221 -480
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
- data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
- data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
- data/lib/capybara/selenium/driver.rb +203 -86
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +88 -14
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +124 -0
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +89 -0
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +26 -0
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
- data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
- data/lib/capybara/selenium/extensions/find.rb +110 -0
- data/lib/capybara/selenium/extensions/html5_drag.rb +191 -22
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/extensions/scroll.rb +78 -0
- data/lib/capybara/selenium/logger_suppressor.rb +34 -0
- data/lib/capybara/selenium/node.rb +298 -93
- data/lib/capybara/selenium/nodes/chrome_node.rb +100 -8
- data/lib/capybara/selenium/nodes/edge_node.rb +104 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +131 -0
- data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
- data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/atoms.rb +18 -0
- data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
- data/lib/capybara/selenium/patches/logs.rb +45 -0
- data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -3
- data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
- data/lib/capybara/server/animation_disabler.rb +4 -3
- data/lib/capybara/server/checker.rb +6 -2
- data/lib/capybara/server/middleware.rb +23 -13
- data/lib/capybara/server.rb +30 -7
- data/lib/capybara/session/config.rb +14 -10
- data/lib/capybara/session/matchers.rb +11 -7
- data/lib/capybara/session.rb +152 -111
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +101 -10
- data/lib/capybara/spec/session/all_spec.rb +96 -6
- data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +29 -0
- data/lib/capybara/spec/session/assert_current_path_spec.rb +5 -2
- data/lib/capybara/spec/session/assert_selector_spec.rb +0 -10
- data/lib/capybara/spec/session/assert_style_spec.rb +4 -4
- data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
- data/lib/capybara/spec/session/attach_file_spec.rb +63 -36
- data/lib/capybara/spec/session/check_spec.rb +10 -4
- data/lib/capybara/spec/session/choose_spec.rb +8 -2
- data/lib/capybara/spec/session/click_button_spec.rb +117 -61
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +16 -0
- data/lib/capybara/spec/session/click_link_spec.rb +17 -6
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +40 -39
- data/lib/capybara/spec/session/evaluate_script_spec.rb +13 -0
- data/lib/capybara/spec/session/execute_script_spec.rb +1 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +47 -6
- data/lib/capybara/spec/session/find_field_spec.rb +1 -1
- data/lib/capybara/spec/session/find_spec.rb +74 -4
- data/lib/capybara/spec/session/first_spec.rb +1 -1
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +13 -1
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +12 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +1 -1
- data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
- data/lib/capybara/spec/session/has_button_spec.rb +16 -0
- data/lib/capybara/spec/session/has_css_spec.rb +122 -12
- data/lib/capybara/spec/session/has_current_path_spec.rb +6 -4
- data/lib/capybara/spec/session/has_field_spec.rb +55 -0
- data/lib/capybara/spec/session/has_select_spec.rb +34 -6
- data/lib/capybara/spec/session/has_selector_spec.rb +11 -4
- data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
- data/lib/capybara/spec/session/has_table_spec.rb +166 -0
- data/lib/capybara/spec/session/has_text_spec.rb +48 -1
- data/lib/capybara/spec/session/has_xpath_spec.rb +17 -0
- data/lib/capybara/spec/session/html_spec.rb +7 -0
- data/lib/capybara/spec/session/matches_style_spec.rb +35 -0
- data/lib/capybara/spec/session/node_spec.rb +643 -18
- data/lib/capybara/spec/session/node_wrapper_spec.rb +1 -1
- data/lib/capybara/spec/session/refresh_spec.rb +4 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +23 -8
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
- data/lib/capybara/spec/session/scroll_spec.rb +117 -0
- data/lib/capybara/spec/session/select_spec.rb +10 -10
- data/lib/capybara/spec/session/selectors_spec.rb +36 -5
- data/lib/capybara/spec/session/uncheck_spec.rb +2 -2
- data/lib/capybara/spec/session/unselect_spec.rb +1 -1
- data/lib/capybara/spec/session/window/become_closed_spec.rb +20 -17
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +4 -0
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +4 -0
- data/lib/capybara/spec/session/window/window_spec.rb +59 -58
- data/lib/capybara/spec/session/window/windows_spec.rb +4 -0
- data/lib/capybara/spec/session/within_spec.rb +23 -0
- data/lib/capybara/spec/spec_helper.rb +16 -6
- data/lib/capybara/spec/test_app.rb +28 -23
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/form.erb +48 -7
- data/lib/capybara/spec/views/frame_child.erb +3 -2
- data/lib/capybara/spec/views/frame_one.erb +1 -0
- data/lib/capybara/spec/views/obscured.erb +47 -0
- data/lib/capybara/spec/views/offset.erb +32 -0
- data/lib/capybara/spec/views/react.erb +45 -0
- data/lib/capybara/spec/views/scroll.erb +20 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/tables.erb +67 -0
- data/lib/capybara/spec/views/with_animation.erb +29 -1
- data/lib/capybara/spec/views/with_dragula.erb +24 -0
- data/lib/capybara/spec/views/with_hover.erb +1 -0
- data/lib/capybara/spec/views/with_hover1.erb +10 -0
- data/lib/capybara/spec/views/with_html.erb +32 -6
- data/lib/capybara/spec/views/with_js.erb +3 -1
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_scope_other.erb +6 -0
- data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +11 -11
- data/lib/capybara.rb +118 -111
- data/spec/basic_node_spec.rb +14 -3
- data/spec/capybara_spec.rb +29 -29
- data/spec/css_builder_spec.rb +101 -0
- data/spec/dsl_spec.rb +46 -21
- data/spec/filter_set_spec.rb +5 -5
- data/spec/fixtures/selenium_driver_rspec_failure.rb +1 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
- data/spec/minitest_spec.rb +18 -4
- data/spec/minitest_spec_spec.rb +59 -44
- data/spec/rack_test_spec.rb +117 -89
- data/spec/regexp_dissassembler_spec.rb +250 -0
- data/spec/result_spec.rb +51 -49
- data/spec/rspec/features_spec.rb +3 -0
- data/spec/rspec/shared_spec_matchers.rb +112 -97
- data/spec/rspec_spec.rb +35 -17
- data/spec/sauce_spec_chrome.rb +43 -0
- data/spec/selector_spec.rb +244 -28
- data/spec/selenium_spec_chrome.rb +125 -54
- data/spec/selenium_spec_chrome_remote.rb +26 -12
- data/spec/selenium_spec_edge.rb +23 -8
- data/spec/selenium_spec_firefox.rb +208 -0
- data/spec/selenium_spec_firefox_remote.rb +15 -18
- data/spec/selenium_spec_ie.rb +82 -13
- data/spec/selenium_spec_safari.rb +148 -0
- data/spec/server_spec.rb +118 -77
- data/spec/session_spec.rb +19 -3
- data/spec/shared_selenium_node.rb +83 -0
- data/spec/shared_selenium_session.rb +110 -65
- data/spec/spec_helper.rb +57 -9
- data/spec/xpath_builder_spec.rb +93 -0
- metadata +257 -17
- data/lib/capybara/rspec/compound.rb +0 -94
- data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +0 -49
- data/lib/capybara/selenium/nodes/marionette_node.rb +0 -121
- data/lib/capybara/spec/session/has_style_spec.rb +0 -25
- data/spec/selenium_spec_marionette.rb +0 -172
@@ -28,27 +28,30 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
28
28
|
end
|
29
29
|
|
30
30
|
describe 'exit codes' do
|
31
|
+
let(:env) { { 'SELENIUM_BROWSER' => session.driver.options[:browser].to_s } }
|
32
|
+
let!(:orig_dir) { Dir.getwd }
|
33
|
+
|
31
34
|
before do
|
32
|
-
@current_dir = Dir.getwd
|
33
35
|
Dir.chdir(File.join(File.dirname(__FILE__), '..'))
|
34
|
-
@env = { 'SELENIUM_BROWSER' => session.driver.options[:browser].to_s }
|
35
36
|
end
|
36
37
|
|
37
38
|
after do
|
38
|
-
Dir.chdir(
|
39
|
+
Dir.chdir(orig_dir)
|
39
40
|
end
|
40
41
|
|
41
42
|
it 'should have return code 1 when running selenium_driver_rspec_failure.rb' do
|
42
43
|
skip 'only setup for local non-headless' if headless_or_remote?
|
44
|
+
skip 'Not setup for edge' if edge?(session)
|
43
45
|
|
44
|
-
system(
|
46
|
+
system(env, 'rspec spec/fixtures/selenium_driver_rspec_failure.rb', out: File::NULL, err: File::NULL)
|
45
47
|
expect($CHILD_STATUS.exitstatus).to eq(1)
|
46
48
|
end
|
47
49
|
|
48
50
|
it 'should have return code 0 when running selenium_driver_rspec_success.rb' do
|
49
51
|
skip 'only setup for local non-headless' if headless_or_remote?
|
52
|
+
skip 'Not setup for edge' if edge?(session)
|
50
53
|
|
51
|
-
system(
|
54
|
+
system(env, 'rspec spec/fixtures/selenium_driver_rspec_success.rb', out: File::NULL, err: File::NULL)
|
52
55
|
expect($CHILD_STATUS.exitstatus).to eq(0)
|
53
56
|
end
|
54
57
|
end
|
@@ -69,8 +72,9 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
72
|
-
|
75
|
+
describe '#fill_in_with empty string and no options' do
|
73
76
|
it 'should trigger change when clearing a field' do
|
77
|
+
pending "safaridriver doesn't trigger change for clear" if safari?(session)
|
74
78
|
session.visit('/with_js')
|
75
79
|
session.fill_in('with_change_event', with: '')
|
76
80
|
# click outside the field to trigger the change event
|
@@ -79,7 +83,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
79
83
|
end
|
80
84
|
end
|
81
85
|
|
82
|
-
|
86
|
+
describe '#fill_in with { :clear => :backspace } fill_option', requires: [:js] do
|
83
87
|
before do
|
84
88
|
# Firefox has an issue with change events if the main window doesn't think it's focused
|
85
89
|
session.execute_script('window.focus()')
|
@@ -115,6 +119,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
115
119
|
|
116
120
|
it 'should only trigger onchange once' do
|
117
121
|
session.visit('/with_js')
|
122
|
+
sleep 2 if safari?(session) # Safari needs a delay (to load event handlers maybe ???)
|
118
123
|
session.fill_in('with_change_event',
|
119
124
|
with: 'some value',
|
120
125
|
fill_options: { clear: :backspace })
|
@@ -139,22 +144,34 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
139
144
|
with: '',
|
140
145
|
fill_options: { clear: :backspace })
|
141
146
|
# click outside the field to trigger the change event
|
142
|
-
session.find(:css, 'body').click
|
147
|
+
# session.find(:css, 'body').click
|
148
|
+
session.find(:css, 'h1', text: 'FooBar').click
|
143
149
|
expect(session).to have_xpath('//p[@class="input_event_triggered"]', count: 13)
|
144
150
|
end
|
145
151
|
end
|
146
152
|
|
147
|
-
|
153
|
+
describe '#fill_in with { clear: :none } fill_options' do
|
148
154
|
it 'should append to content in a field' do
|
155
|
+
pending 'Safari overwrites by default - need to figure out a workaround' if safari?(session)
|
156
|
+
|
149
157
|
session.visit('/form')
|
150
158
|
session.fill_in('form_first_name',
|
151
159
|
with: 'Harry',
|
152
160
|
fill_options: { clear: :none })
|
153
161
|
expect(session.find(:fillable_field, 'form_first_name').value).to eq('JohnHarry')
|
154
162
|
end
|
163
|
+
|
164
|
+
it 'works with rapid fill' do
|
165
|
+
pending 'Safari overwrites by default - need to figure out a workaround' if safari?(session)
|
166
|
+
|
167
|
+
long_string = (0...60).map { |i| ((i % 26) + 65).chr }.join
|
168
|
+
session.visit('/form')
|
169
|
+
session.fill_in('form_first_name', with: long_string, fill_options: { clear: :none })
|
170
|
+
expect(session.find(:fillable_field, 'form_first_name').value).to eq('John' + long_string)
|
171
|
+
end
|
155
172
|
end
|
156
173
|
|
157
|
-
|
174
|
+
describe '#fill_in with Date' do
|
158
175
|
before do
|
159
176
|
session.visit('/form')
|
160
177
|
session.find(:css, '#form_date').execute_script <<-JS
|
@@ -165,17 +182,20 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
165
182
|
});
|
166
183
|
JS
|
167
184
|
# work around weird FF issue where it would create an extra focus issue in some cases
|
168
|
-
session.find(:css, '
|
185
|
+
session.find(:css, 'h1', text: 'Form').click
|
186
|
+
# session.find(:css, 'body').click
|
169
187
|
end
|
170
188
|
|
171
189
|
it 'should generate standard events on changing value' do
|
172
190
|
pending "IE 11 doesn't support date input type" if ie?(session)
|
191
|
+
pending "Safari doesn't support date input type" if safari?(session)
|
173
192
|
session.fill_in('form_date', with: Date.today)
|
174
193
|
expect(session.evaluate_script('window.capybara_formDateFiredEvents')).to eq %w[focus input change]
|
175
194
|
end
|
176
195
|
|
177
196
|
it 'should not generate input and change events if the value is not changed' do
|
178
197
|
pending "IE 11 doesn't support date input type" if ie?(session)
|
198
|
+
pending "Safari doesn't support date input type" if safari?(session)
|
179
199
|
session.fill_in('form_date', with: Date.today)
|
180
200
|
session.fill_in('form_date', with: Date.today)
|
181
201
|
# Chrome adds an extra focus for some reason - ok for now
|
@@ -183,7 +203,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
183
203
|
end
|
184
204
|
end
|
185
205
|
|
186
|
-
|
206
|
+
describe '#fill_in with { clear: Array } fill_options' do
|
187
207
|
it 'should pass the array through to the element' do
|
188
208
|
# this is mainly for use with [[:control, 'a'], :backspace] - however since that is platform dependant I'm testing with something less useful
|
189
209
|
session.visit('/form')
|
@@ -199,14 +219,14 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
199
219
|
# this is here because it is testing for an XPath that is specific to the algorithm used in the selenium driver
|
200
220
|
session.visit('/path')
|
201
221
|
element = session.find(:link, 'Second Link')
|
202
|
-
expect(element.path).to eq('/HTML/BODY/DIV[2]/A[1]')
|
222
|
+
expect(element.path).to eq('/HTML/BODY[1]/DIV[2]/A[1]')
|
203
223
|
end
|
204
224
|
|
205
225
|
it 'handles namespaces in xhtml' do
|
206
226
|
pending "IE 11 doesn't handle all XPath querys (namespace-uri, etc)" if ie?(session)
|
207
227
|
session.visit '/with_namespace'
|
208
228
|
rect = session.find(:css, 'div svg rect:first-of-type')
|
209
|
-
expect(rect.path).to eq("/HTML/BODY/DIV
|
229
|
+
expect(rect.path).to eq("/HTML/BODY[1]/DIV[1]/*[local-name()='svg' and namespace-uri()='http://www.w3.org/2000/svg'][1]/*[local-name()='rect' and namespace-uri()='http://www.w3.org/2000/svg'][1]")
|
210
230
|
expect(session.find(:xpath, rect.path)).to eq rect
|
211
231
|
end
|
212
232
|
|
@@ -214,7 +234,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
214
234
|
pending "IE 11 doesn't handle all XPath querys (namespace-uri, etc)" if ie?(session)
|
215
235
|
session.visit '/with_html5_svg'
|
216
236
|
rect = session.find(:css, 'div svg rect:first-of-type')
|
217
|
-
expect(rect.path).to eq("/HTML/BODY/DIV
|
237
|
+
expect(rect.path).to eq("/HTML/BODY[1]/DIV[1]/*[local-name()='svg' and namespace-uri()='http://www.w3.org/2000/svg'][1]/*[local-name()='rect' and namespace-uri()='http://www.w3.org/2000/svg'][1]")
|
218
238
|
expect(session.find(:xpath, rect.path)).to eq rect
|
219
239
|
end
|
220
240
|
|
@@ -263,6 +283,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
263
283
|
|
264
284
|
describe '#evaluate_async_script' do
|
265
285
|
it 'will timeout if the script takes too long' do
|
286
|
+
skip 'safaridriver returns the wrong error type' if safari?(session)
|
266
287
|
session.visit('/with_js')
|
267
288
|
expect do
|
268
289
|
session.using_wait_time(1) do
|
@@ -287,50 +308,37 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
287
308
|
describe 'Element#click' do
|
288
309
|
it 'should handle fixed headers/footers' do
|
289
310
|
session.visit('/with_fixed_header_footer')
|
290
|
-
|
291
|
-
|
311
|
+
session.using_wait_time(2) do
|
312
|
+
session.find(:link, 'Go to root').click
|
313
|
+
end
|
292
314
|
expect(session).to have_current_path('/')
|
293
315
|
end
|
294
316
|
end
|
295
317
|
|
296
|
-
describe '
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
session
|
304
|
-
|
305
|
-
target = session.find('//div[@id="drop_html5"]')
|
306
|
-
element.drag_to(target)
|
307
|
-
expect(session).to have_xpath('//div[contains(., "HTML5 Dropped drag_html5")]')
|
308
|
-
end
|
318
|
+
describe 'Capybara#Node#attach_file' do
|
319
|
+
it 'can attach a directory' do
|
320
|
+
pending "Geckodriver doesn't support uploading a directory" if firefox?(session)
|
321
|
+
pending "Selenium remote doesn't support transferring a directory" if remote?(session)
|
322
|
+
pending "Headless Chrome doesn't support directory upload - https://bugs.chromium.org/p/chromedriver/issues/detail?id=2521&q=directory%20upload&colspec=ID%20Status%20Pri%20Owner%20Summary" if chrome?(session) && ENV['HEADLESS']
|
323
|
+
pending "IE doesn't support uploading a directory" if ie?(session)
|
324
|
+
pending 'Chrome/chromedriver 73 breaks this' if chrome?(session) && chrome_gte?(73, session) && chrome_lt?(75, session)
|
325
|
+
pending "Safari doesn't support uploading a directory" if safari?(session)
|
326
|
+
# pending "Edge/msedgedriver doesn't support directory upload" if edge?(session) && edge_gte?(75, session)
|
309
327
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
element.drag_to(target)
|
316
|
-
sleep 1
|
317
|
-
expect(session).not_to have_xpath('//div[contains(., "HTML5 Dropped drag_html5")]')
|
328
|
+
session.visit('/form')
|
329
|
+
test_file_dir = File.expand_path('./fixtures', File.dirname(__FILE__))
|
330
|
+
session.attach_file('Directory Upload', test_file_dir)
|
331
|
+
session.click_button('Upload Multiple')
|
332
|
+
expect(session.body).to include('5 | ') # number of files
|
318
333
|
end
|
319
334
|
|
320
|
-
it '
|
321
|
-
|
322
|
-
element = session.find('//div[@id="drag_html5_scroll"]')
|
323
|
-
target = session.find('//div[@id="drop_html5_scroll"]')
|
324
|
-
element.drag_to(target)
|
325
|
-
expect(session).to have_xpath('//div[contains(., "HTML5 Dropped drag_html5_scroll")]')
|
326
|
-
end
|
335
|
+
it 'can attach a relative file' do
|
336
|
+
pending 'Geckdoriver on windows requires alternate file separator which path expansion replaces' if Gem.win_platform? && firefox?(session)
|
327
337
|
|
328
|
-
|
329
|
-
session.
|
330
|
-
|
331
|
-
|
332
|
-
link.drag_to target
|
333
|
-
expect(session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
|
338
|
+
session.visit('/form')
|
339
|
+
session.attach_file('Single Document', 'spec/fixtures/capybara.csv')
|
340
|
+
session.click_button('Upload Single')
|
341
|
+
expect(session.body).to include('Content-type: text/csv')
|
334
342
|
end
|
335
343
|
end
|
336
344
|
|
@@ -342,44 +350,45 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
342
350
|
end
|
343
351
|
end
|
344
352
|
|
353
|
+
# rubocop:disable RSpec/InstanceVariable
|
345
354
|
describe 'Capybara#disable_animation' do
|
346
355
|
context 'when set to `true`' do
|
347
356
|
before(:context) do # rubocop:disable RSpec/BeforeAfterAll
|
357
|
+
skip "Safari doesn't support multiple sessions" if safari?(session)
|
348
358
|
# NOTE: Although Capybara.SpecHelper.reset! sets Capybara.disable_animation to false,
|
349
359
|
# it doesn't affect any of these tests because the settings are applied per-session
|
350
360
|
Capybara.disable_animation = true
|
351
361
|
@animation_session = Capybara::Session.new(session.mode, TestApp.new)
|
352
362
|
end
|
353
363
|
|
354
|
-
after(:context) do # rubocop:disable RSpec/BeforeAfterAll
|
355
|
-
@animation_session = nil
|
356
|
-
end
|
357
|
-
|
358
364
|
it 'should disable CSS transitions' do
|
359
365
|
@animation_session.visit('with_animation')
|
360
366
|
@animation_session.click_link('transition me away')
|
361
367
|
expect(@animation_session).to have_no_link('transition me away', wait: 0.5)
|
362
368
|
end
|
363
369
|
|
364
|
-
it 'should disable CSS animations' do
|
370
|
+
it 'should disable CSS animations (set to 0s)' do
|
365
371
|
@animation_session.visit('with_animation')
|
366
372
|
@animation_session.click_link('animate me away')
|
367
373
|
expect(@animation_session).to have_no_link('animate me away', wait: 0.5)
|
368
374
|
end
|
375
|
+
|
376
|
+
it 'should disable CSS animations on pseudo elements (set to 0s)' do
|
377
|
+
@animation_session.visit('with_animation')
|
378
|
+
@animation_session.find_link('animate me away').right_click
|
379
|
+
expect(@animation_session).to have_content('Animation Ended', wait: 0.1)
|
380
|
+
end
|
369
381
|
end
|
370
382
|
|
371
383
|
context 'if we pass in css that matches elements' do
|
372
384
|
before(:context) do # rubocop:disable RSpec/BeforeAfterAll
|
385
|
+
skip "safaridriver doesn't support multiple sessions" if safari?(session)
|
373
386
|
# NOTE: Although Capybara.SpecHelper.reset! sets Capybara.disable_animation to false,
|
374
387
|
# it doesn't affect any of these tests because the settings are applied per-session
|
375
388
|
Capybara.disable_animation = '#with_animation a'
|
376
389
|
@animation_session_with_matching_css = Capybara::Session.new(session.mode, TestApp.new)
|
377
390
|
end
|
378
391
|
|
379
|
-
after(:context) do # rubocop:disable RSpec/BeforeAfterAll
|
380
|
-
@animation_session_with_matching_css = nil
|
381
|
-
end
|
382
|
-
|
383
392
|
it 'should disable CSS transitions' do
|
384
393
|
@animation_session_with_matching_css.visit('with_animation')
|
385
394
|
@animation_session_with_matching_css.click_link('transition me away')
|
@@ -395,16 +404,13 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
395
404
|
|
396
405
|
context 'if we pass in css that does not match elements' do
|
397
406
|
before(:context) do # rubocop:disable RSpec/BeforeAfterAll
|
407
|
+
skip "Safari doesn't support multiple sessions" if safari?(session)
|
398
408
|
# NOTE: Although Capybara.SpecHelper.reset! sets Capybara.disable_animation to false,
|
399
409
|
# it doesn't affect any of these tests because the settings are applied per-session
|
400
410
|
Capybara.disable_animation = '.this-class-matches-nothing'
|
401
411
|
@animation_session_without_matching_css = Capybara::Session.new(session.mode, TestApp.new)
|
402
412
|
end
|
403
413
|
|
404
|
-
after(:context) do # rubocop:disable RSpec/BeforeAfterAll
|
405
|
-
@animation_session_without_matching_css = nil
|
406
|
-
end
|
407
|
-
|
408
414
|
it 'should not disable CSS transitions' do
|
409
415
|
@animation_session_without_matching_css.visit('with_animation')
|
410
416
|
@animation_session_without_matching_css.click_link('transition me away')
|
@@ -422,15 +428,54 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
422
428
|
end
|
423
429
|
end
|
424
430
|
end
|
431
|
+
# rubocop:enable RSpec/InstanceVariable
|
425
432
|
|
426
433
|
describe ':element selector' do
|
427
434
|
it 'can find html5 svg elements' do
|
428
435
|
session.visit('with_html5_svg')
|
429
436
|
expect(session).to have_selector(:element, :svg)
|
430
|
-
expect(session).to have_selector(:element, :rect, visible:
|
437
|
+
expect(session).to have_selector(:element, :rect, visible: :visible)
|
431
438
|
expect(session).to have_selector(:element, :circle)
|
432
439
|
expect(session).to have_selector(:element, :linearGradient, visible: :all)
|
433
440
|
end
|
441
|
+
|
442
|
+
it 'can query attributes with strange characters' do
|
443
|
+
session.visit('/form')
|
444
|
+
expect(session).to have_selector(:element, "{custom}": true)
|
445
|
+
expect(session).to have_selector(:element, "{custom}": 'abcdef')
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
describe 'with react' do
|
450
|
+
context 'controlled components' do
|
451
|
+
it 'can set and clear a text field' do
|
452
|
+
skip "This test doesn't support older browsers" if ie?(session)
|
453
|
+
|
454
|
+
session.visit 'react'
|
455
|
+
|
456
|
+
session.fill_in('Name:', with: 'abc')
|
457
|
+
session.accept_prompt 'A name was submitted: abc' do
|
458
|
+
session.click_button('Submit')
|
459
|
+
end
|
460
|
+
|
461
|
+
session.fill_in('Name:', with: '')
|
462
|
+
session.accept_prompt(/A name was submitted: $/) do
|
463
|
+
session.click_button('Submit')
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
it 'works with rapid fill' do
|
468
|
+
skip "This test doesn't support older browsers" if ie?(session)
|
469
|
+
|
470
|
+
session.visit 'react'
|
471
|
+
long_string = (0...60).map { |i| ((i % 26) + 65).chr }.join
|
472
|
+
|
473
|
+
session.fill_in('Name:', with: long_string)
|
474
|
+
session.accept_prompt "A name was submitted: #{long_string}" do
|
475
|
+
session.click_button('Submit')
|
476
|
+
end
|
477
|
+
end
|
478
|
+
end
|
434
479
|
end
|
435
480
|
end
|
436
481
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,52 +1,100 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rspec/expectations'
|
4
|
+
require 'webdrivers' if ENV['CI'] || ENV['WEBDRIVERS']
|
5
|
+
require 'selenium_statistics'
|
6
|
+
if ENV['TRAVIS']
|
7
|
+
require 'coveralls'
|
8
|
+
Coveralls.wear! do
|
9
|
+
add_filter '/lib/capybara/driver/'
|
10
|
+
add_filter '/lib/capybara/registrations/'
|
11
|
+
end
|
12
|
+
end
|
4
13
|
require 'capybara/spec/spec_helper'
|
5
|
-
require 'webdrivers' if ENV['CI']
|
6
14
|
|
7
15
|
module Capybara
|
8
16
|
module SpecHelper
|
9
|
-
def
|
17
|
+
def firefox?(session)
|
10
18
|
browser_name(session) == :firefox &&
|
11
|
-
|
19
|
+
((defined?(::Selenium::WebDriver::VERSION) && (::Selenium::WebDriver::VERSION.to_f >= 4)) ||
|
20
|
+
session.driver.browser.capabilities.is_a?(::Selenium::WebDriver::Remote::W3C::Capabilities))
|
12
21
|
end
|
13
22
|
|
14
|
-
def
|
15
|
-
|
23
|
+
def firefox_lt?(version, session)
|
24
|
+
firefox?(session) && (session.driver.browser.capabilities[:browser_version].to_f < version)
|
16
25
|
end
|
17
26
|
|
18
|
-
def
|
19
|
-
|
27
|
+
def firefox_gte?(version, session)
|
28
|
+
firefox?(session) && (session.driver.browser.capabilities[:browser_version].to_f >= version)
|
20
29
|
end
|
21
30
|
|
22
31
|
def chrome?(session)
|
23
32
|
browser_name(session) == :chrome
|
24
33
|
end
|
25
34
|
|
35
|
+
def chrome_version(session)
|
36
|
+
(session.driver.browser.capabilities[:browser_version] ||
|
37
|
+
session.driver.browser.capabilities[:version]).to_f
|
38
|
+
end
|
39
|
+
|
26
40
|
def chrome_lt?(version, session)
|
27
|
-
chrome?(session) && (session
|
41
|
+
chrome?(session) && (chrome_version(session) < version)
|
28
42
|
end
|
29
43
|
|
30
44
|
def chrome_gte?(version, session)
|
31
|
-
chrome?(session) && (session
|
45
|
+
chrome?(session) && (chrome_version(session) >= version)
|
32
46
|
end
|
33
47
|
|
34
48
|
def edge?(session)
|
49
|
+
browser_name(session).to_s.start_with?('edge')
|
50
|
+
end
|
51
|
+
|
52
|
+
def legacy_edge?(session)
|
35
53
|
browser_name(session) == :edge
|
36
54
|
end
|
37
55
|
|
56
|
+
def edge_lt?(version, session)
|
57
|
+
edge?(session) && (chrome_version(session) < version)
|
58
|
+
end
|
59
|
+
|
60
|
+
def edge_gte?(version, session)
|
61
|
+
edge?(session) && (chrome_version(session) >= version)
|
62
|
+
end
|
63
|
+
|
38
64
|
def ie?(session)
|
39
65
|
%i[internet_explorer ie].include?(browser_name(session))
|
40
66
|
end
|
41
67
|
|
68
|
+
def safari?(session)
|
69
|
+
%i[safari Safari Safari_Technology_Preview].include?(browser_name(session))
|
70
|
+
end
|
71
|
+
|
42
72
|
def browser_name(session)
|
43
73
|
session.driver.browser.browser if session.respond_to?(:driver)
|
44
74
|
end
|
75
|
+
|
76
|
+
def remote?(session)
|
77
|
+
session.driver.browser.is_a? ::Selenium::WebDriver::Remote::Driver
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.log_selenium_driver_version(mod)
|
81
|
+
mod = mod::Service if ::Selenium::WebDriver::Service.respond_to? :driver_path
|
82
|
+
path = mod.driver_path
|
83
|
+
path = path.call if path.respond_to? :call
|
84
|
+
$stdout.puts `#{path.gsub(' ', '\ ')} --version`
|
85
|
+
end
|
45
86
|
end
|
46
87
|
end
|
47
88
|
|
48
89
|
RSpec.configure do |config|
|
49
90
|
Capybara::SpecHelper.configure(config)
|
91
|
+
config.expect_with :rspec do |expectations|
|
92
|
+
expectations.syntax = :expect
|
93
|
+
end
|
94
|
+
config.mock_with :rspec do |mocks|
|
95
|
+
mocks.verify_partial_doubles = true
|
96
|
+
end
|
50
97
|
config.filter_run_including focus_: true unless ENV['CI']
|
51
98
|
config.run_all_when_everything_filtered = true
|
99
|
+
config.after(:suite) { SeleniumStatistics.print_results }
|
52
100
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
# rubocop:disable RSpec/InstanceVariable
|
6
|
+
RSpec.describe Capybara::Selector::XPathBuilder do
|
7
|
+
let :builder do
|
8
|
+
::Capybara::Selector::XPathBuilder.new(@xpath)
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'add_attribute_conditions' do
|
12
|
+
it 'adds a single string condition to a single selector' do
|
13
|
+
@xpath = './/div'
|
14
|
+
selector = builder.add_attribute_conditions(random: 'abc')
|
15
|
+
expect(selector).to eq %((.//div)[(./@random = 'abc')])
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'adds multiple string conditions to a single selector' do
|
19
|
+
@xpath = './/div'
|
20
|
+
selector = builder.add_attribute_conditions(random: 'abc', other: 'def')
|
21
|
+
expect(selector).to eq %(((.//div)[(./@random = 'abc')])[(./@other = 'def')])
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'adds a single string condition to a multiple selector' do
|
25
|
+
@xpath = XPath.descendant(:div, :ul)
|
26
|
+
selector = builder.add_attribute_conditions(random: 'abc')
|
27
|
+
expect(selector.to_s).to eq @xpath[XPath.attr(:random) == 'abc'].to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'adds multiple string conditions to a multiple selector' do
|
31
|
+
@xpath = XPath.descendant(:div, :ul)
|
32
|
+
selector = builder.add_attribute_conditions(random: 'abc', other: 'def')
|
33
|
+
expect(selector.to_s).to eq %(.//*[self::div | self::ul][(./@random = 'abc')][(./@other = 'def')])
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'adds simple regexp conditions to a single selector' do
|
37
|
+
@xpath = XPath.descendant(:div)
|
38
|
+
selector = builder.add_attribute_conditions(random: /abc/, other: /def/)
|
39
|
+
expect(selector.to_s).to eq %(.//div[./@random[contains(., 'abc')]][./@other[contains(., 'def')]])
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'adds wildcard regexp conditions to a single selector' do
|
43
|
+
@xpath = './/div'
|
44
|
+
selector = builder.add_attribute_conditions(random: /abc.*def/, other: /def.*ghi/)
|
45
|
+
expect(selector).to eq %(((.//div)[./@random[(contains(., 'abc') and contains(., 'def'))]])[./@other[(contains(., 'def') and contains(., 'ghi'))]])
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'adds alternated regexp conditions to a single selector' do
|
49
|
+
@xpath = XPath.descendant(:div)
|
50
|
+
selector = builder.add_attribute_conditions(random: /abc|def/, other: /def|ghi/)
|
51
|
+
expect(selector.to_s).to eq %(.//div[./@random[(contains(., 'abc') or contains(., 'def'))]][./@other[(contains(., 'def') or contains(., 'ghi'))]])
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'adds alternated regexp conditions to a multiple selector' do
|
55
|
+
@xpath = XPath.descendant(:div, :ul)
|
56
|
+
selector = builder.add_attribute_conditions(other: /def.*ghi|jkl/)
|
57
|
+
expect(selector.to_s).to eq %(.//*[self::div | self::ul][./@other[((contains(., 'def') and contains(., 'ghi')) or contains(., 'jkl'))]])
|
58
|
+
end
|
59
|
+
|
60
|
+
it "returns original selector when regexp can't be substringed" do
|
61
|
+
@xpath = './/div'
|
62
|
+
selector = builder.add_attribute_conditions(other: /.+/)
|
63
|
+
expect(selector).to eq '(.//div)[./@other]'
|
64
|
+
end
|
65
|
+
|
66
|
+
context ':class' do
|
67
|
+
it 'handles string' do
|
68
|
+
@xpath = './/a'
|
69
|
+
selector = builder.add_attribute_conditions(class: 'my_class')
|
70
|
+
expect(selector).to eq %((.//a)[contains(concat(' ', normalize-space(./@class), ' '), ' my_class ')])
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'handles negated strings' do
|
74
|
+
@xpath = XPath.descendant(:a)
|
75
|
+
selector = builder.add_attribute_conditions(class: '!my_class')
|
76
|
+
expect(selector.to_s).to eq @xpath[!XPath.attr(:class).contains_word('my_class')].to_s
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'handles array of strings' do
|
80
|
+
@xpath = './/a'
|
81
|
+
selector = builder.add_attribute_conditions(class: %w[my_class my_other_class])
|
82
|
+
expect(selector).to eq %((.//a)[(contains(concat(' ', normalize-space(./@class), ' '), ' my_class ') and contains(concat(' ', normalize-space(./@class), ' '), ' my_other_class '))])
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'handles array of string when negated included' do
|
86
|
+
@xpath = XPath.descendant(:a)
|
87
|
+
selector = builder.add_attribute_conditions(class: %w[my_class !my_other_class])
|
88
|
+
expect(selector.to_s).to eq @xpath[XPath.attr(:class).contains_word('my_class') & !XPath.attr(:class).contains_word('my_other_class')].to_s
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
# rubocop:enable RSpec/InstanceVariable
|