capybara 3.23.0 → 3.35.3
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 +264 -11
- data/README.md +10 -6
- data/lib/capybara.rb +20 -8
- data/lib/capybara/config.rb +10 -8
- data/lib/capybara/cucumber.rb +1 -1
- data/lib/capybara/driver/base.rb +4 -0
- data/lib/capybara/driver/node.rb +4 -0
- data/lib/capybara/dsl.rb +10 -2
- data/lib/capybara/helpers.rb +28 -2
- data/lib/capybara/minitest.rb +232 -144
- data/lib/capybara/minitest/spec.rb +156 -97
- data/lib/capybara/node/actions.rb +36 -36
- data/lib/capybara/node/base.rb +6 -6
- data/lib/capybara/node/document.rb +2 -2
- data/lib/capybara/node/document_matchers.rb +3 -3
- data/lib/capybara/node/element.rb +77 -33
- data/lib/capybara/node/finders.rb +24 -17
- data/lib/capybara/node/matchers.rb +79 -64
- data/lib/capybara/node/simple.rb +11 -4
- data/lib/capybara/queries/ancestor_query.rb +6 -10
- data/lib/capybara/queries/base_query.rb +2 -1
- data/lib/capybara/queries/current_path_query.rb +14 -4
- data/lib/capybara/queries/selector_query.rb +259 -23
- data/lib/capybara/queries/sibling_query.rb +5 -11
- data/lib/capybara/queries/style_query.rb +1 -1
- data/lib/capybara/queries/text_query.rb +13 -1
- data/lib/capybara/rack_test/browser.rb +13 -4
- data/lib/capybara/rack_test/driver.rb +2 -1
- data/lib/capybara/rack_test/form.rb +2 -2
- data/lib/capybara/rack_test/node.rb +42 -6
- data/lib/capybara/registration_container.rb +44 -0
- data/lib/capybara/registrations/drivers.rb +18 -12
- data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
- data/lib/capybara/registrations/servers.rb +9 -2
- data/lib/capybara/result.rb +39 -19
- data/lib/capybara/rspec.rb +2 -0
- data/lib/capybara/rspec/matcher_proxies.rb +5 -5
- data/lib/capybara/rspec/matchers.rb +97 -74
- data/lib/capybara/rspec/matchers/base.rb +19 -6
- data/lib/capybara/rspec/matchers/count_sugar.rb +2 -1
- data/lib/capybara/rspec/matchers/have_ancestor.rb +5 -7
- data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
- data/lib/capybara/rspec/matchers/have_selector.rb +15 -10
- data/lib/capybara/rspec/matchers/have_sibling.rb +4 -7
- data/lib/capybara/rspec/matchers/have_text.rb +4 -7
- data/lib/capybara/rspec/matchers/have_title.rb +2 -2
- data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
- data/lib/capybara/rspec/matchers/match_style.rb +7 -2
- data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
- data/lib/capybara/selector.rb +46 -19
- data/lib/capybara/selector/builders/css_builder.rb +10 -6
- data/lib/capybara/selector/builders/xpath_builder.rb +4 -2
- data/lib/capybara/selector/css.rb +1 -1
- data/lib/capybara/selector/definition.rb +13 -11
- data/lib/capybara/selector/definition/button.rb +32 -15
- data/lib/capybara/selector/definition/checkbox.rb +2 -2
- data/lib/capybara/selector/definition/css.rb +3 -1
- data/lib/capybara/selector/definition/datalist_input.rb +2 -2
- data/lib/capybara/selector/definition/datalist_option.rb +1 -1
- data/lib/capybara/selector/definition/element.rb +3 -2
- data/lib/capybara/selector/definition/field.rb +1 -1
- data/lib/capybara/selector/definition/file_field.rb +1 -1
- data/lib/capybara/selector/definition/fillable_field.rb +2 -2
- data/lib/capybara/selector/definition/label.rb +5 -3
- data/lib/capybara/selector/definition/link.rb +8 -0
- data/lib/capybara/selector/definition/option.rb +1 -1
- data/lib/capybara/selector/definition/radio_button.rb +2 -2
- data/lib/capybara/selector/definition/select.rb +33 -14
- data/lib/capybara/selector/definition/table.rb +6 -3
- data/lib/capybara/selector/definition/table_row.rb +2 -2
- data/lib/capybara/selector/filter_set.rb +13 -11
- data/lib/capybara/selector/filters/base.rb +6 -1
- data/lib/capybara/selector/filters/locator_filter.rb +1 -1
- data/lib/capybara/selector/regexp_disassembler.rb +7 -0
- data/lib/capybara/selector/selector.rb +13 -3
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -1
- data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -1
- data/lib/capybara/selenium/atoms/src/getAttribute.js +1 -1
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +10 -10
- data/lib/capybara/selenium/driver.rb +86 -24
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +24 -21
- data/lib/capybara/selenium/driver_specializations/edge_driver.rb +21 -19
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +17 -1
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +0 -4
- data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
- data/lib/capybara/selenium/extensions/find.rb +37 -26
- data/lib/capybara/selenium/extensions/html5_drag.rb +55 -11
- data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
- data/lib/capybara/selenium/extensions/scroll.rb +8 -10
- data/lib/capybara/selenium/logger_suppressor.rb +8 -2
- data/lib/capybara/selenium/node.rb +160 -40
- data/lib/capybara/selenium/nodes/chrome_node.rb +72 -12
- data/lib/capybara/selenium/nodes/edge_node.rb +32 -14
- data/lib/capybara/selenium/nodes/firefox_node.rb +28 -32
- data/lib/capybara/selenium/nodes/safari_node.rb +5 -29
- data/lib/capybara/selenium/patches/action_pauser.rb +26 -0
- data/lib/capybara/selenium/patches/atoms.rb +4 -4
- data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
- data/lib/capybara/selenium/patches/logs.rb +32 -7
- data/lib/capybara/server.rb +19 -3
- data/lib/capybara/server/animation_disabler.rb +8 -3
- data/lib/capybara/server/checker.rb +1 -1
- data/lib/capybara/server/middleware.rb +22 -10
- data/lib/capybara/session.rb +66 -40
- data/lib/capybara/session/config.rb +11 -3
- data/lib/capybara/session/matchers.rb +11 -11
- data/lib/capybara/spec/public/offset.js +6 -0
- data/lib/capybara/spec/public/test.js +75 -7
- data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
- data/lib/capybara/spec/session/all_spec.rb +60 -5
- data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
- data/lib/capybara/spec/session/assert_text_spec.rb +9 -5
- data/lib/capybara/spec/session/check_spec.rb +6 -0
- data/lib/capybara/spec/session/click_button_spec.rb +16 -0
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
- data/lib/capybara/spec/session/current_url_spec.rb +11 -1
- data/lib/capybara/spec/session/fill_in_spec.rb +29 -0
- data/lib/capybara/spec/session/find_spec.rb +55 -0
- data/lib/capybara/spec/session/has_ancestor_spec.rb +2 -0
- data/lib/capybara/spec/session/has_button_spec.rb +51 -0
- data/lib/capybara/spec/session/has_css_spec.rb +26 -4
- data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
- data/lib/capybara/spec/session/has_field_spec.rb +34 -0
- data/lib/capybara/spec/session/has_select_spec.rb +32 -4
- data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
- data/lib/capybara/spec/session/has_table_spec.rb +51 -5
- data/lib/capybara/spec/session/has_text_spec.rb +30 -0
- data/lib/capybara/spec/session/html_spec.rb +1 -1
- data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
- data/lib/capybara/spec/session/node_spec.rb +394 -9
- data/lib/capybara/spec/session/refresh_spec.rb +2 -1
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
- data/lib/capybara/spec/session/save_page_spec.rb +4 -4
- data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -15
- data/lib/capybara/spec/session/selectors_spec.rb +16 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
- data/lib/capybara/spec/session/window/window_spec.rb +8 -8
- data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
- data/lib/capybara/spec/spec_helper.rb +14 -14
- data/lib/capybara/spec/test_app.rb +27 -21
- data/lib/capybara/spec/views/form.erb +47 -4
- data/lib/capybara/spec/views/offset.erb +32 -0
- data/lib/capybara/spec/views/spatial.erb +31 -0
- data/lib/capybara/spec/views/with_animation.erb +37 -1
- data/lib/capybara/spec/views/with_dragula.erb +24 -0
- data/lib/capybara/spec/views/with_html.erb +24 -2
- data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
- data/lib/capybara/spec/views/with_js.erb +4 -1
- data/lib/capybara/spec/views/with_jstree.erb +26 -0
- data/lib/capybara/spec/views/with_sortable_js.erb +1 -1
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +3 -7
- data/spec/basic_node_spec.rb +15 -14
- data/spec/capybara_spec.rb +28 -28
- data/spec/dsl_spec.rb +16 -3
- 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 +3 -2
- data/spec/minitest_spec_spec.rb +46 -46
- data/spec/rack_test_spec.rb +38 -15
- data/spec/regexp_dissassembler_spec.rb +52 -38
- data/spec/result_spec.rb +43 -32
- data/spec/rspec/features_spec.rb +4 -1
- data/spec/rspec/scenarios_spec.rb +4 -0
- data/spec/rspec/shared_spec_matchers.rb +68 -56
- data/spec/rspec_spec.rb +9 -5
- data/spec/selector_spec.rb +32 -17
- data/spec/selenium_spec_chrome.rb +78 -11
- data/spec/selenium_spec_chrome_remote.rb +23 -6
- data/spec/selenium_spec_edge.rb +15 -12
- data/spec/selenium_spec_firefox.rb +24 -19
- data/spec/selenium_spec_firefox_remote.rb +0 -8
- data/spec/selenium_spec_ie.rb +1 -6
- data/spec/server_spec.rb +106 -44
- data/spec/session_spec.rb +5 -5
- data/spec/shared_selenium_node.rb +56 -2
- data/spec/shared_selenium_session.rb +122 -15
- data/spec/spec_helper.rb +2 -2
- metadata +63 -17
- data/lib/capybara/spec/session/source_spec.rb +0 -0
@@ -143,10 +143,56 @@ Capybara::SpecHelper.spec '#has_no_table?' do
|
|
143
143
|
])
|
144
144
|
end
|
145
145
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
146
|
+
context 'using :with_cols' do
|
147
|
+
it 'should consider a single column' do
|
148
|
+
expect(@session).to have_no_table('Vertical Headers', with_cols:
|
149
|
+
[
|
150
|
+
{ 'First Name' => 'Joe' }
|
151
|
+
])
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should be true even if the last column does exist' do
|
155
|
+
expect(@session).to have_no_table('Vertical Headers', with_cols:
|
156
|
+
[
|
157
|
+
{
|
158
|
+
'First Name' => 'What?',
|
159
|
+
'What?' => 'Walpole',
|
160
|
+
'City' => 'Oceanside' # This line makes the example fail
|
161
|
+
}
|
162
|
+
])
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'should be true if none of the columns exist' do
|
166
|
+
expect(@session).to have_no_table('Vertical Headers', with_cols:
|
167
|
+
[
|
168
|
+
{
|
169
|
+
'First Name' => 'What?',
|
170
|
+
'What?' => 'Walpole',
|
171
|
+
'City' => 'What?'
|
172
|
+
}
|
173
|
+
])
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'should be true if the first column does match' do
|
177
|
+
expect(@session).to have_no_table('Vertical Headers', with_cols:
|
178
|
+
[
|
179
|
+
{
|
180
|
+
'First Name' => 'Thomas',
|
181
|
+
'Last Name' => 'What',
|
182
|
+
'City' => 'What'
|
183
|
+
}
|
184
|
+
])
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'should be true if none of the columns match' do
|
188
|
+
expect(@session).to have_no_table('Vertical Headers', with_cols:
|
189
|
+
[
|
190
|
+
{
|
191
|
+
'First Name' => 'What',
|
192
|
+
'Last Name' => 'What',
|
193
|
+
'City' => 'What'
|
194
|
+
}
|
195
|
+
])
|
196
|
+
end
|
151
197
|
end
|
152
198
|
end
|
@@ -111,6 +111,30 @@ Capybara::SpecHelper.spec '#has_text?' do
|
|
111
111
|
expect(@session).not_to have_text(/xxxxyzzz/)
|
112
112
|
end
|
113
113
|
|
114
|
+
context 'with object implementing to_s and to_hash' do
|
115
|
+
it 'should work if the object is passed alone' do
|
116
|
+
with_to_hash = Class.new do
|
117
|
+
def to_s; '42' end
|
118
|
+
def to_hash; { value: 'Other hash' } end
|
119
|
+
end.new
|
120
|
+
@session.visit('/with_html')
|
121
|
+
expect(@session).to have_text(with_to_hash)
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should work if passed with empty options' do
|
125
|
+
with_to_hash = Class.new do
|
126
|
+
def to_s; '42' end
|
127
|
+
def to_hash; { value: 'Other hash' } end
|
128
|
+
end.new
|
129
|
+
@session.visit('/with_html')
|
130
|
+
if RUBY_VERSION >= '2.7'
|
131
|
+
expect(@session).to have_text(:visible, with_to_hash, **{})
|
132
|
+
else
|
133
|
+
expect(@session).to have_text(:visible, with_to_hash, {})
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
114
138
|
context 'with exact: true option' do
|
115
139
|
it 'should be true if text matches exactly' do
|
116
140
|
@session.visit('/with_html')
|
@@ -139,6 +163,12 @@ Capybara::SpecHelper.spec '#has_text?' do
|
|
139
163
|
expect(@session).to have_text(nil)
|
140
164
|
end
|
141
165
|
|
166
|
+
it 'should warn when passed nil' do
|
167
|
+
@session.visit('/with_html')
|
168
|
+
expect_any_instance_of(Kernel).to receive(:warn).with(/Checking for expected text of nil is confusing/) # rubocop:disable RSpec/AnyInstance
|
169
|
+
expect(@session).to have_text(nil)
|
170
|
+
end
|
171
|
+
|
142
172
|
it 'should wait for text to appear', requires: [:js] do
|
143
173
|
Capybara.using_wait_time(3) do
|
144
174
|
@session.visit('/with_js')
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
3
|
+
# NOTE: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
|
4
4
|
# because of the methods being tested. In tests using Capybara this type of behavior should be implemented
|
5
5
|
# using Capybara provided assertions with builtin waiting behavior.
|
6
6
|
|
@@ -28,8 +28,8 @@ Capybara::SpecHelper.spec '#matches_style?', requires: [:css] do
|
|
28
28
|
output(/have_style is deprecated/).to_stderr
|
29
29
|
|
30
30
|
el = @session.find(:css, '#first')
|
31
|
-
allow(
|
31
|
+
allow(Capybara::Helpers).to receive(:warn).and_return(nil)
|
32
32
|
el.has_style?('display' => /^bl/)
|
33
|
-
expect(
|
33
|
+
expect(Capybara::Helpers).to have_received(:warn)
|
34
34
|
end
|
35
35
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
3
|
+
# NOTE: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
|
4
4
|
# because of the methods being tested. In tests using Capybara this type of behavior should be implemented
|
5
5
|
# using Capybara provided assertions with builtin waiting behavior.
|
6
6
|
|
@@ -233,8 +233,9 @@ Capybara::SpecHelper.spec 'node' do
|
|
233
233
|
end
|
234
234
|
|
235
235
|
describe '#visible?' do
|
236
|
+
before { Capybara.ignore_hidden_elements = false }
|
237
|
+
|
236
238
|
it 'should extract node visibility' do
|
237
|
-
Capybara.ignore_hidden_elements = false
|
238
239
|
expect(@session.first('//a')).to be_visible
|
239
240
|
|
240
241
|
expect(@session.find('//div[@id="hidden"]')).not_to be_visible
|
@@ -245,15 +246,39 @@ Capybara::SpecHelper.spec 'node' do
|
|
245
246
|
end
|
246
247
|
|
247
248
|
it 'template elements should not be visible' do
|
248
|
-
Capybara.ignore_hidden_elements = false
|
249
249
|
expect(@session.find('//template')).not_to be_visible
|
250
250
|
end
|
251
251
|
|
252
252
|
it 'should be boolean' do
|
253
|
-
Capybara.ignore_hidden_elements = false
|
254
253
|
expect(@session.first('//a').visible?).to be true
|
255
254
|
expect(@session.find('//div[@id="hidden"]').visible?).to be false
|
256
255
|
end
|
256
|
+
|
257
|
+
it 'closed details > summary elements and descendants should be visible' do
|
258
|
+
expect(@session.find(:css, '#closed_details summary')).to be_visible
|
259
|
+
expect(@session.find(:css, '#closed_details summary h6')).to be_visible
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'details non-summary descendants should be non-visible when closed' do
|
263
|
+
descendants = @session.all(:css, '#closed_details > *:not(summary), #closed_details > *:not(summary) *', minimum: 2)
|
264
|
+
expect(descendants).not_to include(be_visible)
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'deatils descendants should be visible when open' do
|
268
|
+
descendants = @session.all(:css, '#open_details *')
|
269
|
+
expect(descendants).to all(be_visible)
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'works when details is toggled open and closed' do
|
273
|
+
@session.find(:css, '#closed_details > summary').click
|
274
|
+
expect(@session).to have_css('#closed_details *', visible: :visible, count: 5)
|
275
|
+
.and(have_no_css('#closed_details *', visible: :hidden))
|
276
|
+
|
277
|
+
@session.find(:css, '#closed_details > summary').click
|
278
|
+
descendants_css = '#closed_details > *:not(summary), #closed_details > *:not(summary) *'
|
279
|
+
expect(@session).to have_no_css(descendants_css, visible: :visible)
|
280
|
+
.and(have_css(descendants_css, visible: :hidden, count: 3))
|
281
|
+
end
|
257
282
|
end
|
258
283
|
|
259
284
|
describe '#obscured?', requires: [:css] do
|
@@ -363,8 +388,8 @@ Capybara::SpecHelper.spec 'node' do
|
|
363
388
|
|
364
389
|
describe '#==' do
|
365
390
|
it 'preserve object identity' do
|
366
|
-
expect(@session.find('//h1') == @session.find('//h1')).to be true # rubocop:disable Lint/
|
367
|
-
expect(@session.find('//h1') === @session.find('//h1')).to be true # rubocop:disable Style/CaseEquality, Lint/
|
391
|
+
expect(@session.find('//h1') == @session.find('//h1')).to be true # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
|
392
|
+
expect(@session.find('//h1') === @session.find('//h1')).to be true # rubocop:disable Style/CaseEquality, Lint/BinaryOperatorWithIdenticalOperands
|
368
393
|
expect(@session.find('//h1').eql?(@session.find('//h1'))).to be false
|
369
394
|
end
|
370
395
|
|
@@ -384,6 +409,17 @@ Capybara::SpecHelper.spec 'node' do
|
|
384
409
|
element = @session.find(:link, 'Second Link')
|
385
410
|
expect(@session.find(:xpath, element.path)).to eq(element)
|
386
411
|
end
|
412
|
+
|
413
|
+
it 'reports when element in shadow dom', requires: [:shadow_dom] do
|
414
|
+
@session.visit('/with_js')
|
415
|
+
shadow = @session.find(:css, '#shadow')
|
416
|
+
element = @session.evaluate_script(<<~JS, shadow)
|
417
|
+
(function(root){
|
418
|
+
return root.shadowRoot.querySelector('span');
|
419
|
+
})(arguments[0])
|
420
|
+
JS
|
421
|
+
expect(element.path).to eq '(: Shadow DOM element - no XPath :)'
|
422
|
+
end
|
387
423
|
end
|
388
424
|
|
389
425
|
describe '#trigger', requires: %i[js trigger] do
|
@@ -419,6 +455,74 @@ Capybara::SpecHelper.spec 'node' do
|
|
419
455
|
expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
|
420
456
|
end
|
421
457
|
|
458
|
+
it 'should work with Dragula' do
|
459
|
+
@session.visit('/with_dragula')
|
460
|
+
@session.within(:css, '#sortable.ready') do
|
461
|
+
src = @session.find('div', text: 'Item 1')
|
462
|
+
target = @session.find('div', text: 'Item 3')
|
463
|
+
src.drag_to target
|
464
|
+
expect(@session).to have_content(/Item 2.*Item 1/, normalize_ws: true)
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
468
|
+
it 'should work with jsTree' do
|
469
|
+
@session.visit('/with_jstree')
|
470
|
+
@session.within(:css, '#container') do
|
471
|
+
@session.assert_text(/A.*B.*C/m)
|
472
|
+
source = @session.find(:css, '#j1_1_anchor')
|
473
|
+
target = @session.find(:css, '#j1_2_anchor')
|
474
|
+
|
475
|
+
source.drag_to(target)
|
476
|
+
|
477
|
+
@session.assert_no_text(/A.*B.*C/m)
|
478
|
+
@session.assert_text(/B.*C/m)
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
it 'should simulate a single held down modifier key' do
|
483
|
+
%I[
|
484
|
+
alt
|
485
|
+
ctrl
|
486
|
+
meta
|
487
|
+
shift
|
488
|
+
].each do |modifier_key|
|
489
|
+
@session.visit('/with_js')
|
490
|
+
|
491
|
+
element = @session.find('//div[@id="drag"]')
|
492
|
+
target = @session.find('//div[@id="drop"]')
|
493
|
+
|
494
|
+
element.drag_to(target, drop_modifiers: modifier_key)
|
495
|
+
expect(@session).to have_css('div.drag_start', exact_text: 'Dragged!')
|
496
|
+
expect(@session).to have_xpath("//div[contains(., 'Dropped!-#{modifier_key}')]")
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
it 'should simulate multiple held down modifier keys' do
|
501
|
+
@session.visit('/with_js')
|
502
|
+
|
503
|
+
element = @session.find('//div[@id="drag"]')
|
504
|
+
target = @session.find('//div[@id="drop"]')
|
505
|
+
|
506
|
+
modifier_keys = %I[alt ctrl meta shift]
|
507
|
+
|
508
|
+
element.drag_to(target, drop_modifiers: modifier_keys)
|
509
|
+
expect(@session).to have_xpath("//div[contains(., 'Dropped!-#{modifier_keys.join('-')}')]")
|
510
|
+
end
|
511
|
+
|
512
|
+
it 'should support key aliases' do
|
513
|
+
{ control: :ctrl,
|
514
|
+
command: :meta,
|
515
|
+
cmd: :meta }.each do |(key_alias, key)|
|
516
|
+
@session.visit('/with_js')
|
517
|
+
|
518
|
+
element = @session.find('//div[@id="drag"]')
|
519
|
+
target = @session.find('//div[@id="drop"]')
|
520
|
+
|
521
|
+
element.drag_to(target, drop_modifiers: [key_alias])
|
522
|
+
expect(target).to have_text("Dropped!-#{key}", exact: true)
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
422
526
|
context 'HTML5', requires: %i[js html5_drag] do
|
423
527
|
it 'should HTML5 drag and drop an object' do
|
424
528
|
@session.visit('/with_js')
|
@@ -428,6 +532,14 @@ Capybara::SpecHelper.spec 'node' do
|
|
428
532
|
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5")]')
|
429
533
|
end
|
430
534
|
|
535
|
+
it 'should HTML5 drag and drop an object child' do
|
536
|
+
@session.visit('/with_js')
|
537
|
+
element = @session.find('//div[@id="drag_html5"]/p')
|
538
|
+
target = @session.find('//div[@id="drop_html5"]')
|
539
|
+
element.drag_to(target)
|
540
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5")]')
|
541
|
+
end
|
542
|
+
|
431
543
|
it 'should set clientX/Y in dragover events' do
|
432
544
|
@session.visit('/with_js')
|
433
545
|
element = @session.find('//div[@id="drag_html5"]')
|
@@ -436,6 +548,26 @@ Capybara::SpecHelper.spec 'node' do
|
|
436
548
|
expect(@session).to have_css('div.log', text: /DragOver with client position: [1-9]\d*,[1-9]\d*/, count: 2)
|
437
549
|
end
|
438
550
|
|
551
|
+
it 'should preserve clientX/Y from last dragover event' do
|
552
|
+
@session.visit('/with_js')
|
553
|
+
element = @session.find('//div[@id="drag_html5"]')
|
554
|
+
target = @session.find('//div[@id="drop_html5"]')
|
555
|
+
element.drag_to(target)
|
556
|
+
|
557
|
+
conditions = %w[DragLeave Drop DragEnd].map do |text|
|
558
|
+
have_css('div.log', text: text)
|
559
|
+
end
|
560
|
+
expect(@session).to(conditions.reduce { |memo, cond| memo.and(cond) })
|
561
|
+
|
562
|
+
# The first "DragOver" div is inserted by the last dragover event dispatched
|
563
|
+
drag_over_div = @session.first('//div[@class="log" and starts-with(text(), "DragOver")]')
|
564
|
+
position = drag_over_div.text.sub('DragOver ', '')
|
565
|
+
|
566
|
+
expect(@session).to have_css('div.log', text: /DragLeave #{position}/, count: 1)
|
567
|
+
expect(@session).to have_css('div.log', text: /Drop #{position}/, count: 1)
|
568
|
+
expect(@session).to have_css('div.log', text: /DragEnd #{position}/, count: 1)
|
569
|
+
end
|
570
|
+
|
439
571
|
it 'should not HTML5 drag and drop on a non HTML5 drop element' do
|
440
572
|
@session.visit('/with_js')
|
441
573
|
element = @session.find('//div[@id="drag_html5"]')
|
@@ -471,6 +603,54 @@ Capybara::SpecHelper.spec 'node' do
|
|
471
603
|
expect(@session).to have_content(/Item 3.*Item 1/, normalize_ws: true)
|
472
604
|
end
|
473
605
|
end
|
606
|
+
|
607
|
+
it 'should drag HTML5 default draggable element child' do
|
608
|
+
@session.visit('/with_js')
|
609
|
+
source = @session.find_link('drag_link_html5').find(:css, 'p')
|
610
|
+
target = @session.find(:id, 'drop_html5')
|
611
|
+
source.drag_to target
|
612
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
|
613
|
+
end
|
614
|
+
|
615
|
+
it 'should simulate a single held down modifier key' do
|
616
|
+
%I[alt ctrl meta shift].each do |modifier_key|
|
617
|
+
@session.visit('/with_js')
|
618
|
+
|
619
|
+
element = @session.find('//div[@id="drag_html5"]')
|
620
|
+
target = @session.find('//div[@id="drop_html5"]')
|
621
|
+
|
622
|
+
element.drag_to(target, drop_modifiers: modifier_key)
|
623
|
+
|
624
|
+
expect(@session).to have_css('div.drag_start', exact_text: 'HTML5 Dragged!')
|
625
|
+
expect(@session).to have_xpath("//div[contains(., 'HTML5 Dropped string: text/plain drag_html5-#{modifier_key}')]")
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
it 'should simulate multiple held down modifier keys' do
|
630
|
+
@session.visit('/with_js')
|
631
|
+
|
632
|
+
element = @session.find('//div[@id="drag_html5"]')
|
633
|
+
target = @session.find('//div[@id="drop_html5"]')
|
634
|
+
|
635
|
+
modifier_keys = %I[alt ctrl meta shift]
|
636
|
+
|
637
|
+
element.drag_to(target, drop_modifiers: modifier_keys)
|
638
|
+
expect(@session).to have_xpath("//div[contains(., 'HTML5 Dropped string: text/plain drag_html5-#{modifier_keys.join('-')}')]")
|
639
|
+
end
|
640
|
+
|
641
|
+
it 'should support key aliases' do
|
642
|
+
{ control: :ctrl,
|
643
|
+
command: :meta,
|
644
|
+
cmd: :meta }.each do |(key_alias, key)|
|
645
|
+
@session.visit('/with_js')
|
646
|
+
|
647
|
+
element = @session.find('//div[@id="drag_html5"]')
|
648
|
+
target = @session.find('//div[@id="drop_html5"]')
|
649
|
+
|
650
|
+
element.drag_to(target, drop_modifiers: [key_alias])
|
651
|
+
expect(target).to have_text(%r{^HTML5 Dropped string: text/plain drag_html5-#{key}$}m, exact: true)
|
652
|
+
end
|
653
|
+
end
|
474
654
|
end
|
475
655
|
end
|
476
656
|
|
@@ -502,6 +682,15 @@ Capybara::SpecHelper.spec 'node' do
|
|
502
682
|
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain Some dropped text")]')
|
503
683
|
end
|
504
684
|
|
685
|
+
it 'can drop a pathname' do
|
686
|
+
@session.visit('/with_js')
|
687
|
+
target = @session.find('//div[@id="drop_html5"]')
|
688
|
+
target.drop(
|
689
|
+
Pathname.new(with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__))))
|
690
|
+
)
|
691
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
|
692
|
+
end
|
693
|
+
|
505
694
|
it 'can drop multiple strings' do
|
506
695
|
@session.visit('/with_js')
|
507
696
|
target = @session.find('//div[@id="drop_html5"]')
|
@@ -589,7 +778,7 @@ Capybara::SpecHelper.spec 'node' do
|
|
589
778
|
@session.visit('with_js')
|
590
779
|
@session.find(:css, '#click-test').click(x: 5, y: 5)
|
591
780
|
link = @session.find(:link, 'has-been-clicked')
|
592
|
-
locations = link.text.match(/^Has been clicked at (?<x>[\d
|
781
|
+
locations = link.text.match(/^Has been clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
|
593
782
|
# Resulting click location should be very close to 0, 0 relative to top left corner of the element, but may not be exact due to
|
594
783
|
# integer/float conversions and rounding.
|
595
784
|
expect(locations[:x].to_f).to be_within(1).of(5)
|
@@ -635,6 +824,67 @@ Capybara::SpecHelper.spec 'node' do
|
|
635
824
|
JS
|
636
825
|
expect { obscured.click(wait: 0) }.to(raise_error { |e| expect(e).to be_an_invalid_element_error(@session) })
|
637
826
|
end
|
827
|
+
|
828
|
+
context 'offset', requires: [:js] do
|
829
|
+
before do
|
830
|
+
@session.visit('/offset')
|
831
|
+
end
|
832
|
+
|
833
|
+
let :clicker do
|
834
|
+
@session.find(:id, 'clicker')
|
835
|
+
end
|
836
|
+
|
837
|
+
context 'when w3c_click_offset is false' do
|
838
|
+
before do
|
839
|
+
Capybara.w3c_click_offset = false
|
840
|
+
end
|
841
|
+
|
842
|
+
it 'should offset from top left of element' do
|
843
|
+
clicker.click(x: 10, y: 5)
|
844
|
+
expect(@session).to have_text(/clicked at 110,105/)
|
845
|
+
end
|
846
|
+
|
847
|
+
it 'should offset outside the element' do
|
848
|
+
clicker.click(x: -15, y: -10)
|
849
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
850
|
+
end
|
851
|
+
|
852
|
+
it 'should default to click the middle' do
|
853
|
+
clicker.click
|
854
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
855
|
+
end
|
856
|
+
end
|
857
|
+
|
858
|
+
context 'when w3c_click_offset is true' do
|
859
|
+
before do
|
860
|
+
Capybara.w3c_click_offset = true
|
861
|
+
end
|
862
|
+
|
863
|
+
it 'should offset from center of element' do
|
864
|
+
clicker.click(x: 10, y: 5)
|
865
|
+
expect(@session).to have_text(/clicked at 160,155/)
|
866
|
+
end
|
867
|
+
|
868
|
+
it 'should offset outside from center of element' do
|
869
|
+
clicker.click(x: -65, y: -60)
|
870
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
871
|
+
end
|
872
|
+
|
873
|
+
it 'should default to click the middle' do
|
874
|
+
clicker.click
|
875
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
876
|
+
end
|
877
|
+
end
|
878
|
+
end
|
879
|
+
|
880
|
+
context 'delay', requires: [:js] do
|
881
|
+
it 'should delay the mouse up' do
|
882
|
+
@session.visit('with_js')
|
883
|
+
@session.find(:css, '#click-test').click(delay: 2)
|
884
|
+
delay = @session.evaluate_script('window.click_delay')
|
885
|
+
expect(delay).to be >= 2
|
886
|
+
end
|
887
|
+
end
|
638
888
|
end
|
639
889
|
|
640
890
|
describe '#double_click', requires: [:js] do
|
@@ -654,7 +904,7 @@ Capybara::SpecHelper.spec 'node' do
|
|
654
904
|
@session.visit('with_js')
|
655
905
|
@session.find(:css, '#click-test').double_click(x: 10, y: 5)
|
656
906
|
link = @session.find(:link, 'has-been-double-clicked')
|
657
|
-
locations = link.text.match(/^Has been double clicked at (?<x>[\d
|
907
|
+
locations = link.text.match(/^Has been double clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
|
658
908
|
# Resulting click location should be very close to 10, 5 relative to top left corner of the element, but may not be exact due
|
659
909
|
# to integer/float conversions and rounding.
|
660
910
|
expect(locations[:x].to_f).to be_within(1).of(10)
|
@@ -669,6 +919,58 @@ Capybara::SpecHelper.spec 'node' do
|
|
669
919
|
JS
|
670
920
|
expect { obscured.double_click }.not_to raise_error
|
671
921
|
end
|
922
|
+
|
923
|
+
context 'offset', requires: [:js] do
|
924
|
+
before do
|
925
|
+
@session.visit('/offset')
|
926
|
+
end
|
927
|
+
|
928
|
+
let :clicker do
|
929
|
+
@session.find(:id, 'clicker')
|
930
|
+
end
|
931
|
+
|
932
|
+
context 'when w3c_click_offset is false' do
|
933
|
+
before do
|
934
|
+
Capybara.w3c_click_offset = false
|
935
|
+
end
|
936
|
+
|
937
|
+
it 'should offset from top left of element' do
|
938
|
+
clicker.double_click(x: 10, y: 5)
|
939
|
+
expect(@session).to have_text(/clicked at 110,105/)
|
940
|
+
end
|
941
|
+
|
942
|
+
it 'should offset outside the element' do
|
943
|
+
clicker.double_click(x: -15, y: -10)
|
944
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
945
|
+
end
|
946
|
+
|
947
|
+
it 'should default to click the middle' do
|
948
|
+
clicker.double_click
|
949
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
950
|
+
end
|
951
|
+
end
|
952
|
+
|
953
|
+
context 'when w3c_click_offset is true' do
|
954
|
+
before do
|
955
|
+
Capybara.w3c_click_offset = true
|
956
|
+
end
|
957
|
+
|
958
|
+
it 'should offset from center of element' do
|
959
|
+
clicker.double_click(x: 10, y: 5)
|
960
|
+
expect(@session).to have_text(/clicked at 160,155/)
|
961
|
+
end
|
962
|
+
|
963
|
+
it 'should offset outside from center of element' do
|
964
|
+
clicker.double_click(x: -65, y: -60)
|
965
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
966
|
+
end
|
967
|
+
|
968
|
+
it 'should default to click the middle' do
|
969
|
+
clicker.double_click
|
970
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
971
|
+
end
|
972
|
+
end
|
973
|
+
end
|
672
974
|
end
|
673
975
|
|
674
976
|
describe '#right_click', requires: [:js] do
|
@@ -688,7 +990,7 @@ Capybara::SpecHelper.spec 'node' do
|
|
688
990
|
@session.visit('with_js')
|
689
991
|
@session.find(:css, '#click-test').right_click(x: 10, y: 10)
|
690
992
|
link = @session.find(:link, 'has-been-right-clicked')
|
691
|
-
locations = link.text.match(/^Has been right clicked at (?<x>[\d
|
993
|
+
locations = link.text.match(/^Has been right clicked at (?<x>[\d.-]+),(?<y>[\d.-]+)$/)
|
692
994
|
# Resulting click location should be very close to 10, 10 relative to top left corner of the element, but may not be exact due
|
693
995
|
# to integer/float conversions and rounding
|
694
996
|
expect(locations[:x].to_f).to be_within(1).of(10)
|
@@ -703,6 +1005,67 @@ Capybara::SpecHelper.spec 'node' do
|
|
703
1005
|
JS
|
704
1006
|
expect { obscured.right_click }.not_to raise_error
|
705
1007
|
end
|
1008
|
+
|
1009
|
+
context 'offset', requires: [:js] do
|
1010
|
+
before do
|
1011
|
+
@session.visit('/offset')
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
let :clicker do
|
1015
|
+
@session.find(:id, 'clicker')
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
context 'when w3c_click_offset is false' do
|
1019
|
+
before do
|
1020
|
+
Capybara.w3c_click_offset = false
|
1021
|
+
end
|
1022
|
+
|
1023
|
+
it 'should offset from top left of element' do
|
1024
|
+
clicker.right_click(x: 10, y: 5)
|
1025
|
+
expect(@session).to have_text(/clicked at 110,105/)
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
it 'should offset outside the element' do
|
1029
|
+
clicker.right_click(x: -15, y: -10)
|
1030
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
it 'should default to click the middle' do
|
1034
|
+
clicker.right_click
|
1035
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
1036
|
+
end
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
context 'when w3c_click_offset is true' do
|
1040
|
+
before do
|
1041
|
+
Capybara.w3c_click_offset = true
|
1042
|
+
end
|
1043
|
+
|
1044
|
+
it 'should offset from center of element' do
|
1045
|
+
clicker.right_click(x: 10, y: 5)
|
1046
|
+
expect(@session).to have_text(/clicked at 160,155/)
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
it 'should offset outside from center of element' do
|
1050
|
+
clicker.right_click(x: -65, y: -60)
|
1051
|
+
expect(@session).to have_text(/clicked at 85,90/)
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
it 'should default to click the middle' do
|
1055
|
+
clicker.right_click
|
1056
|
+
expect(@session).to have_text(/clicked at 150,150/)
|
1057
|
+
end
|
1058
|
+
end
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
context 'delay', requires: [:js] do
|
1062
|
+
it 'should delay the mouse up' do
|
1063
|
+
@session.visit('with_js')
|
1064
|
+
@session.find(:css, '#click-test').right_click(delay: 2)
|
1065
|
+
delay = @session.evaluate_script('window.right_click_delay')
|
1066
|
+
expect(delay).to be >= 2
|
1067
|
+
end
|
1068
|
+
end
|
706
1069
|
end
|
707
1070
|
|
708
1071
|
describe '#send_keys', requires: [:send_keys] do
|
@@ -814,6 +1177,28 @@ Capybara::SpecHelper.spec 'node' do
|
|
814
1177
|
end
|
815
1178
|
|
816
1179
|
describe '#reload', requires: [:js] do
|
1180
|
+
it 'should reload elements found via ancestor with CSS' do
|
1181
|
+
@session.visit('/with_js')
|
1182
|
+
node = @session.find(:css, '#reload-me em').ancestor(:css, 'div')
|
1183
|
+
node.reload
|
1184
|
+
expect(node[:id]).to eq 'reload-me'
|
1185
|
+
end
|
1186
|
+
|
1187
|
+
it 'should reload elements found via ancestor with XPath' do
|
1188
|
+
@session.visit('/with_js')
|
1189
|
+
node = @session.find(:css, '#reload-me em').ancestor(:xpath, './/div')
|
1190
|
+
node.reload
|
1191
|
+
expect(node[:id]).to eq 'reload-me'
|
1192
|
+
end
|
1193
|
+
|
1194
|
+
it 'should reload elements found via sibling' do
|
1195
|
+
@session.visit('/with_js')
|
1196
|
+
node = @session.find(:css, '#the-list li', text: 'Item 1').sibling(:css, 'li')
|
1197
|
+
expect(node.text).to eq 'Item 2'
|
1198
|
+
node.reload
|
1199
|
+
expect(node.text).to eq 'Item 2'
|
1200
|
+
end
|
1201
|
+
|
817
1202
|
context 'without automatic reload' do
|
818
1203
|
before { Capybara.automatic_reload = false }
|
819
1204
|
|