capybara 3.20.1 → 3.21.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 +21 -0
- data/README.md +4 -4
- data/lib/capybara/driver/node.rb +4 -0
- data/lib/capybara/helpers.rb +1 -1
- data/lib/capybara/minitest.rb +4 -4
- data/lib/capybara/node/actions.rb +36 -29
- data/lib/capybara/node/element.rb +123 -82
- data/lib/capybara/node/finders.rb +2 -7
- data/lib/capybara/selector/definition/css.rb +4 -1
- data/lib/capybara/selector/regexp_disassembler.rb +2 -2
- data/lib/capybara/selenium/extensions/html5_drag.rb +63 -0
- data/lib/capybara/selenium/node.rb +4 -0
- data/lib/capybara/selenium/nodes/chrome_node.rb +4 -0
- data/lib/capybara/selenium/nodes/firefox_node.rb +4 -13
- data/lib/capybara/selenium/nodes/ie_node.rb +14 -3
- data/lib/capybara/selenium/nodes/safari_node.rb +0 -13
- data/lib/capybara/spec/public/test.js +29 -3
- data/lib/capybara/spec/session/attach_file_spec.rb +13 -5
- data/lib/capybara/spec/session/has_css_spec.rb +4 -3
- data/lib/capybara/spec/session/node_spec.rb +85 -0
- data/lib/capybara/spec/spec_helper.rb +4 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara.rb +11 -11
- data/spec/selenium_spec_firefox.rb +2 -0
- data/spec/selenium_spec_ie.rb +13 -7
- data/spec/selenium_spec_safari.rb +2 -0
- data/spec/shared_selenium_session.rb +1 -51
- metadata +18 -18
|
@@ -8,19 +8,14 @@ module Capybara
|
|
|
8
8
|
# Find an {Capybara::Node::Element} based on the given arguments. +find+ will raise an error if the element
|
|
9
9
|
# is not found.
|
|
10
10
|
#
|
|
11
|
-
# @!macro waiting_behavior
|
|
12
|
-
# If the driver is capable of executing JavaScript, this method will wait for a set amount of time
|
|
13
|
-
# and continuously retry finding the element until either the element is found or the time
|
|
14
|
-
# expires. The length of time +find+ will wait is controlled through {Capybara.default_max_wait_time}
|
|
15
|
-
# and defaults to 2 seconds.
|
|
16
|
-
# @option options [false, true, Numeric] wait (Capybara.default_max_wait_time) Maximum time to wait for matching element to appear.
|
|
17
|
-
#
|
|
18
11
|
# page.find('#foo').find('.bar')
|
|
19
12
|
# page.find(:xpath, './/div[contains(., "bar")]')
|
|
20
13
|
# page.find('li', text: 'Quox').click_link('Delete')
|
|
21
14
|
#
|
|
22
15
|
# @param (see Capybara::Node::Finders#all)
|
|
23
16
|
#
|
|
17
|
+
# @macro waiting_behavior
|
|
18
|
+
#
|
|
24
19
|
# @!macro system_filters
|
|
25
20
|
# @option options [String, Regexp] text Only find elements which contain this text or match this regexp
|
|
26
21
|
# @option options [String, Boolean] exact_text (Capybara.exact_text) When String the elements contained text must match exactly, when Boolean controls whether the :text option must match exactly
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
Capybara.add_selector(:css, locator_type: [String, Symbol], raw_locator: true) do
|
|
4
|
-
css
|
|
4
|
+
css do |css|
|
|
5
|
+
warn "DEPRECATED: Passing a symbol (#{css.inspect}) as the CSS locator is deprecated - please pass a string instead." if css.is_a? Symbol
|
|
6
|
+
css
|
|
7
|
+
end
|
|
5
8
|
end
|
|
@@ -22,6 +22,69 @@ class Capybara::Selenium::Node
|
|
|
22
22
|
native.property('draggable')
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
def html5_drop(*args)
|
|
26
|
+
if args[0].is_a? String
|
|
27
|
+
input = driver.evaluate_script ATTACH_FILE
|
|
28
|
+
input.set_file(args)
|
|
29
|
+
driver.execute_script DROP_FILE, self, input
|
|
30
|
+
else
|
|
31
|
+
items = args.each_with_object([]) do |arg, arr|
|
|
32
|
+
arg.each_with_object(arr) do |(type, data), arr_|
|
|
33
|
+
arr_ << { type: type, data: data }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
driver.execute_script DROP_STRING, items, self
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
DROP_STRING = <<~JS
|
|
41
|
+
var strings = arguments[0],
|
|
42
|
+
el = arguments[1],
|
|
43
|
+
dt = new DataTransfer(),
|
|
44
|
+
opts = { cancelable: true, bubbles: true, dataTransfer: dt };
|
|
45
|
+
for (var i=0; i < strings.length; i++){
|
|
46
|
+
if (dt.items) {
|
|
47
|
+
dt.items.add(strings[i]['data'], strings[i]['type']);
|
|
48
|
+
} else {
|
|
49
|
+
dt.setData(strings[i]['type'], strings[i]['data']);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
var dropEvent = new DragEvent('drop', opts);
|
|
53
|
+
el.dispatchEvent(dropEvent);
|
|
54
|
+
JS
|
|
55
|
+
|
|
56
|
+
DROP_FILE = <<~JS
|
|
57
|
+
var el = arguments[0],
|
|
58
|
+
input = arguments[1],
|
|
59
|
+
files = input.files,
|
|
60
|
+
dt = new DataTransfer(),
|
|
61
|
+
opts = { cancelable: true, bubbles: true, dataTransfer: dt };
|
|
62
|
+
input.parentElement.removeChild(input);
|
|
63
|
+
if (dt.items){
|
|
64
|
+
for (var i=0; i<files.length; i++){
|
|
65
|
+
dt.items.add(files[i]);
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
Object.defineProperty(dt, "files", {
|
|
69
|
+
value: files,
|
|
70
|
+
writable: false
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
var dropEvent = new DragEvent('drop', opts);
|
|
74
|
+
el.dispatchEvent(dropEvent);
|
|
75
|
+
JS
|
|
76
|
+
|
|
77
|
+
ATTACH_FILE = <<~JS
|
|
78
|
+
(function(){
|
|
79
|
+
var input = document.createElement('INPUT');
|
|
80
|
+
input.type = "file";
|
|
81
|
+
input.id = "_capybara_drop_file";
|
|
82
|
+
input.multiple = true;
|
|
83
|
+
document.body.appendChild(input);
|
|
84
|
+
return input;
|
|
85
|
+
})()
|
|
86
|
+
JS
|
|
87
|
+
|
|
25
88
|
MOUSEDOWN_TRACKER = <<~JS
|
|
26
89
|
document.addEventListener('mousedown', ev => {
|
|
27
90
|
window.capybara_mousedown_prevented = ev.defaultPrevented;
|
|
@@ -137,6 +137,10 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
|
137
137
|
element.scroll_if_needed { browser_action.move_to(element.native).release.perform }
|
|
138
138
|
end
|
|
139
139
|
|
|
140
|
+
def drop(*_)
|
|
141
|
+
raise NotImplementedError, 'Out of browser drop emulation is not implemented for the current browser'
|
|
142
|
+
end
|
|
143
|
+
|
|
140
144
|
def tag_name
|
|
141
145
|
@tag_name ||= native.tag_name.downcase
|
|
142
146
|
end
|
|
@@ -52,6 +52,10 @@ class Capybara::Selenium::FirefoxNode < Capybara::Selenium::Node
|
|
|
52
52
|
html5_drag_to(element)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
def drop(*args)
|
|
56
|
+
html5_drop(*args)
|
|
57
|
+
end
|
|
58
|
+
|
|
55
59
|
def hover
|
|
56
60
|
return super unless browser_version >= 65.0
|
|
57
61
|
|
|
@@ -117,19 +121,6 @@ private
|
|
|
117
121
|
driver.browser.capabilities[:browser_version].to_f
|
|
118
122
|
end
|
|
119
123
|
|
|
120
|
-
DISABLED_BY_FIELDSET_XPATH = XPath.generate do |x|
|
|
121
|
-
x.parent(:fieldset)[
|
|
122
|
-
x.attr(:disabled)
|
|
123
|
-
] + x.ancestor[
|
|
124
|
-
~x.self(:legend) |
|
|
125
|
-
x.preceding_sibling(:legend)
|
|
126
|
-
][
|
|
127
|
-
x.parent(:fieldset)[
|
|
128
|
-
x.attr(:disabled)
|
|
129
|
-
]
|
|
130
|
-
]
|
|
131
|
-
end.to_s.freeze
|
|
132
|
-
|
|
133
124
|
class ModifierKeysStack
|
|
134
125
|
def initialize
|
|
135
126
|
@stack = []
|
|
@@ -4,8 +4,19 @@ require 'capybara/selenium/extensions/html5_drag'
|
|
|
4
4
|
|
|
5
5
|
class Capybara::Selenium::IENode < Capybara::Selenium::Node
|
|
6
6
|
def disabled?
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
|
|
7
|
+
# super
|
|
8
|
+
# optimize to one script call
|
|
9
|
+
driver.evaluate_script <<~JS.delete("\n"), self
|
|
10
|
+
arguments[0].msMatchesSelector('
|
|
11
|
+
:disabled,
|
|
12
|
+
select:disabled *,
|
|
13
|
+
optgroup:disabled *,
|
|
14
|
+
fieldset[disabled],
|
|
15
|
+
fieldset[disabled] > *:not(legend),
|
|
16
|
+
fieldset[disabled] > *:not(legend) *,
|
|
17
|
+
fieldset[disabled] > legend:nth-of-type(n+2),
|
|
18
|
+
fieldset[disabled] > legend:nth-of-type(n+2) *
|
|
19
|
+
')
|
|
20
|
+
JS
|
|
10
21
|
end
|
|
11
22
|
end
|
|
@@ -91,19 +91,6 @@ private
|
|
|
91
91
|
driver.browser.send(:bridge)
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
DISABLED_BY_FIELDSET_XPATH = XPath.generate do |x|
|
|
95
|
-
x.parent(:fieldset)[
|
|
96
|
-
x.attr(:disabled)
|
|
97
|
-
] + x.ancestor[
|
|
98
|
-
~x.self(:legend) |
|
|
99
|
-
x.preceding_sibling(:legend)
|
|
100
|
-
][
|
|
101
|
-
x.parent(:fieldset)[
|
|
102
|
-
x.attr(:disabled)
|
|
103
|
-
]
|
|
104
|
-
]
|
|
105
|
-
end.to_s.freeze
|
|
106
|
-
|
|
107
94
|
def _send_keys(keys, actions = browser_action, down_keys = ModifierKeysStack.new)
|
|
108
95
|
case keys
|
|
109
96
|
when *MODIFIER_KEYS
|
|
@@ -18,7 +18,33 @@ $(function() {
|
|
|
18
18
|
});
|
|
19
19
|
$('#drop_html5, #drop_html5_scroll').on('drop', function(ev){
|
|
20
20
|
ev.preventDefault();
|
|
21
|
-
|
|
21
|
+
var oev = ev.originalEvent;
|
|
22
|
+
if (oev.dataTransfer.items) {
|
|
23
|
+
for (var i = 0; i < oev.dataTransfer.items.length; i++){
|
|
24
|
+
var item = oev.dataTransfer.items[i];
|
|
25
|
+
if (item.kind === 'file'){
|
|
26
|
+
var file = item.getAsFile();
|
|
27
|
+
$(this).append('HTML5 Dropped file: ' + file.name);
|
|
28
|
+
} else {
|
|
29
|
+
var _this = this;
|
|
30
|
+
var callback = (function(type){
|
|
31
|
+
return function(s){
|
|
32
|
+
$(_this).append('HTML5 Dropped string: ' + type + ' ' + s)
|
|
33
|
+
}
|
|
34
|
+
})(item.type);
|
|
35
|
+
item.getAsString(callback);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
$(this).html('HTML5 Dropped ' + oev.dataTransfer.getData("text"));
|
|
40
|
+
for (var i = 0; i < oev.dataTransfer.files.length; i++) {
|
|
41
|
+
$(this).append('HTML5 Dropped file: ' + oev.dataTransfer.files[i].name);
|
|
42
|
+
}
|
|
43
|
+
for (var i = 0; i < oev.dataTransfer.types.length; i++) {
|
|
44
|
+
var type = oev.dataTransfer.types[i];
|
|
45
|
+
$(this).append('HTML5 Dropped string: ' + type + ' ' + oev.dataTransfer.getData(type));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
22
48
|
});
|
|
23
49
|
$('#clickable').click(function(e) {
|
|
24
50
|
var link = $(this);
|
|
@@ -180,7 +206,7 @@ $(function() {
|
|
|
180
206
|
sessionStorage.setItem('session', 'session_value');
|
|
181
207
|
localStorage.setItem('local', 'local value');
|
|
182
208
|
});
|
|
183
|
-
$('#multiple-file').change(function(e){
|
|
184
|
-
$('body').append($('<p class="file_change"
|
|
209
|
+
$('#multiple-file, #hidden_file').change(function(e){
|
|
210
|
+
$('body').append($('<p class="file_change">File input changed</p>'));
|
|
185
211
|
})
|
|
186
212
|
});
|
|
@@ -180,6 +180,12 @@ Capybara::SpecHelper.spec '#attach_file' do
|
|
|
180
180
|
@session.attach_file('hidden_file', with_os_path_separators(__FILE__), make_visible: true)
|
|
181
181
|
expect(@session.evaluate_script('arguments[0].style.display', @session.find(:css, '#hidden_file', visible: :all))).to eq 'none'
|
|
182
182
|
end
|
|
183
|
+
|
|
184
|
+
it 'should fire change' do
|
|
185
|
+
@session.visit('/with_js')
|
|
186
|
+
@session.attach_file('hidden_file', with_os_path_separators(__FILE__), make_visible: true)
|
|
187
|
+
expect(@session).to have_css('.file_change')
|
|
188
|
+
end
|
|
183
189
|
end
|
|
184
190
|
|
|
185
191
|
context 'with a block', requires: %i[js] do
|
|
@@ -198,11 +204,13 @@ Capybara::SpecHelper.spec '#attach_file' do
|
|
|
198
204
|
@session.click_button('awesome')
|
|
199
205
|
expect(extract_results(@session)['hidden_image']).to end_with(File.basename(__FILE__))
|
|
200
206
|
end
|
|
201
|
-
end
|
|
202
207
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
208
|
+
it 'should fire change' do
|
|
209
|
+
@session.visit('/with_js')
|
|
210
|
+
@session.attach_file(with_os_path_separators(__FILE__)) do
|
|
211
|
+
@session.find(:label, 'Label for hidden file input').click
|
|
212
|
+
end
|
|
213
|
+
expect(@session).to have_css('.file_change')
|
|
214
|
+
end
|
|
207
215
|
end
|
|
208
216
|
end
|
|
@@ -10,10 +10,11 @@ Capybara::SpecHelper.spec '#has_css?' do
|
|
|
10
10
|
expect(@session).to have_css('p a#foo')
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
it 'should
|
|
13
|
+
it 'should warn when passed a symbol' do
|
|
14
14
|
# This was never a specifically accepted format but it has worked for a
|
|
15
|
-
# lot of versions.
|
|
16
|
-
# TODO:
|
|
15
|
+
# lot of versions.
|
|
16
|
+
# TODO: Remove in 4.0
|
|
17
|
+
expect_any_instance_of(Kernel).to receive(:warn) # rubocop:disable RSpec/AnyInstance
|
|
17
18
|
expect(@session).to have_css(:p)
|
|
18
19
|
end
|
|
19
20
|
|
|
@@ -242,6 +242,10 @@ Capybara::SpecHelper.spec 'node' do
|
|
|
242
242
|
expect(@session.find('//div[@id="hidden_attr"]')).not_to be_visible
|
|
243
243
|
expect(@session.find('//a[@id="hidden_attr_via_ancestor"]')).not_to be_visible
|
|
244
244
|
expect(@session.find('//input[@id="hidden_input"]')).not_to be_visible
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
it 'template elements should not be visible' do
|
|
248
|
+
Capybara.ignore_hidden_elements = false
|
|
245
249
|
expect(@session.find('//template')).not_to be_visible
|
|
246
250
|
end
|
|
247
251
|
|
|
@@ -414,6 +418,87 @@ Capybara::SpecHelper.spec 'node' do
|
|
|
414
418
|
link.drag_to target
|
|
415
419
|
expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
|
|
416
420
|
end
|
|
421
|
+
|
|
422
|
+
context 'HTML5', requires: %i[js html5_drag] do
|
|
423
|
+
it 'should HTML5 drag and drop an object' do
|
|
424
|
+
@session.visit('/with_js')
|
|
425
|
+
element = @session.find('//div[@id="drag_html5"]')
|
|
426
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
427
|
+
element.drag_to(target)
|
|
428
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5")]')
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
it 'should set clientX/Y in dragover events' do
|
|
432
|
+
@session.visit('/with_js')
|
|
433
|
+
element = @session.find('//div[@id="drag_html5"]')
|
|
434
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
435
|
+
element.drag_to(target)
|
|
436
|
+
expect(@session).to have_css('div.log', text: /DragOver with client position: [1-9]\d*,[1-9]\d*/, count: 2)
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
it 'should not HTML5 drag and drop on a non HTML5 drop element' do
|
|
440
|
+
@session.visit('/with_js')
|
|
441
|
+
element = @session.find('//div[@id="drag_html5"]')
|
|
442
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
443
|
+
target.execute_script("$(this).removeClass('drop');")
|
|
444
|
+
element.drag_to(target)
|
|
445
|
+
sleep 1
|
|
446
|
+
expect(@session).not_to have_xpath('//div[contains(., "HTML5 Dropped")]')
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
it 'should HTML5 drag and drop when scrolling needed' do
|
|
450
|
+
@session.visit('/with_js')
|
|
451
|
+
element = @session.find('//div[@id="drag_html5_scroll"]')
|
|
452
|
+
target = @session.find('//div[@id="drop_html5_scroll"]')
|
|
453
|
+
element.drag_to(target)
|
|
454
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5_scroll")]')
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
it 'should drag HTML5 default draggable elements' do
|
|
458
|
+
@session.visit('/with_js')
|
|
459
|
+
link = @session.find_link('drag_link_html5')
|
|
460
|
+
target = @session.find(:id, 'drop_html5')
|
|
461
|
+
link.drag_to target
|
|
462
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
|
|
463
|
+
end
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
describe 'Element#drop', requires: %i[js html5_drag] do
|
|
468
|
+
it 'can drop a file' do
|
|
469
|
+
@session.visit('/with_js')
|
|
470
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
471
|
+
target.drop(
|
|
472
|
+
with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__)))
|
|
473
|
+
)
|
|
474
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
it 'can drop multiple files' do
|
|
478
|
+
@session.visit('/with_js')
|
|
479
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
480
|
+
target.drop(
|
|
481
|
+
with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__))),
|
|
482
|
+
with_os_path_separators(File.expand_path('../fixtures/test_file.txt', File.dirname(__FILE__)))
|
|
483
|
+
)
|
|
484
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
|
|
485
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: test_file.txt")]')
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
it 'can drop strings' do
|
|
489
|
+
@session.visit('/with_js')
|
|
490
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
491
|
+
target.drop('text/plain' => 'Some dropped text')
|
|
492
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain Some dropped text")]')
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
it 'can drop multiple strings' do
|
|
496
|
+
@session.visit('/with_js')
|
|
497
|
+
target = @session.find('//div[@id="drop_html5"]')
|
|
498
|
+
target.drop('text/plain' => 'Some dropped text', 'text/url' => 'http://www.google.com')
|
|
499
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain Some dropped text")]')
|
|
500
|
+
expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/url http://www.google.com")]')
|
|
501
|
+
end
|
|
417
502
|
end
|
|
418
503
|
|
|
419
504
|
describe '#hover', requires: [:hover] do
|
|
@@ -124,6 +124,10 @@ module Capybara
|
|
|
124
124
|
def be_an_invalid_element_error(session)
|
|
125
125
|
satisfy { |error| session.driver.invalid_element_errors.any? { |e| error.is_a? e } }
|
|
126
126
|
end
|
|
127
|
+
|
|
128
|
+
def with_os_path_separators(path)
|
|
129
|
+
Gem.win_platform? ? path.to_s.tr('/', '\\') : path.to_s
|
|
130
|
+
end
|
|
127
131
|
end
|
|
128
132
|
end
|
|
129
133
|
|
data/lib/capybara/version.rb
CHANGED
data/lib/capybara.rb
CHANGED
|
@@ -73,22 +73,24 @@ module Capybara
|
|
|
73
73
|
# [asset_host = String] Where dynamic assets are hosted - will be prepended to relative asset locations if present (Default: nil)
|
|
74
74
|
# [run_server = Boolean] Whether to start a Rack server for the given Rack app (Default: true)
|
|
75
75
|
# [raise_server_errors = Boolean] Should errors raised in the server be raised in the tests? (Default: true)
|
|
76
|
-
# [server_errors = Array\<Class\>] Error classes that should be raised in the tests if they are raised in the server and
|
|
76
|
+
# [server_errors = Array\<Class\>] Error classes that should be raised in the tests if they are raised in the server and {configure raise_server_errors} is true (Default: [Exception])
|
|
77
77
|
# [default_selector = :css/:xpath] Methods which take a selector use the given type by default (Default: :css)
|
|
78
78
|
# [default_max_wait_time = Numeric] The maximum number of seconds to wait for asynchronous processes to finish (Default: 2)
|
|
79
79
|
# [ignore_hidden_elements = Boolean] Whether to ignore hidden elements on the page (Default: true)
|
|
80
80
|
# [automatic_reload = Boolean] Whether to automatically reload elements as Capybara is waiting (Default: true)
|
|
81
81
|
# [save_path = String] Where to put pages saved through save_(page|screenshot), save_and_open_(page|screenshot) (Default: Dir.pwd)
|
|
82
|
-
# [automatic_label_click = Boolean] Whether Node#choose, Node#check, Node#uncheck will attempt to click the associated label element if the checkbox/radio button are non-visible (Default: false)
|
|
82
|
+
# [automatic_label_click = Boolean] Whether {Capybara::Node::Element#choose Element#choose}, {Capybara::Node::Element#check Element#check}, {Capybara::Node::Element#uncheck Element#uncheck} will attempt to click the associated label element if the checkbox/radio button are non-visible (Default: false)
|
|
83
83
|
# [enable_aria_label = Boolean] Whether fields, links, and buttons will match against aria-label attribute (Default: false)
|
|
84
84
|
# [reuse_server = Boolean] Reuse the server thread between multiple sessions using the same app object (Default: true)
|
|
85
85
|
# [threadsafe = Boolean] Whether sessions can be configured individually (Default: false)
|
|
86
|
-
# [server = Symbol] The name of the registered server to use when running the app under test (Default: :
|
|
87
|
-
# [default_set_options = Hash] The default options passed to Node::set (Default: {})
|
|
86
|
+
# [server = Symbol] The name of the registered server to use when running the app under test (Default: :default which uses puma)
|
|
87
|
+
# [default_set_options = Hash] The default options passed to {Capybara::Node::Element#set Element#set} (Default: {})
|
|
88
88
|
# [test_id = Symbol/String/nil] Optional attribute to match locator aginst with builtin selectors along with id (Default: nil)
|
|
89
|
-
# [predicates_wait = Boolean] Whether
|
|
89
|
+
# [predicates_wait = Boolean] Whether Capybara's predicate matchers use waiting behavior by default (Default: true)
|
|
90
90
|
# [default_normalize_ws = Boolean] Whether text predicates and matchers use normalize whitespace behaviour (Default: false)
|
|
91
91
|
# [allow_gumbo = Boolean] When `nokogumbo` is available, whether it will be used to parse HTML strings (Default: false)
|
|
92
|
+
# [match = :one/:first/:prefer_exact/:smart] The matching strategy to find nodes (Default: :smart)
|
|
93
|
+
# [exact_text = Boolean] Whether the text matchers and `:text` filter match exactly or on substrings (Default: false)
|
|
92
94
|
#
|
|
93
95
|
# === DSL Options
|
|
94
96
|
#
|
|
@@ -201,15 +203,13 @@ module Capybara
|
|
|
201
203
|
# any string containing HTML in the exact same way you would query the current document in a Capybara
|
|
202
204
|
# session.
|
|
203
205
|
#
|
|
204
|
-
#
|
|
205
|
-
#
|
|
206
|
+
# @example A single element
|
|
206
207
|
# node = Capybara.string('<a href="foo">bar</a>')
|
|
207
208
|
# anchor = node.first('a')
|
|
208
209
|
# anchor[:href] #=> 'foo'
|
|
209
210
|
# anchor.text #=> 'bar'
|
|
210
211
|
#
|
|
211
|
-
#
|
|
212
|
-
#
|
|
212
|
+
# @example Multiple elements
|
|
213
213
|
# node = Capybara.string <<-HTML
|
|
214
214
|
# <ul>
|
|
215
215
|
# <li id="home">Home</li>
|
|
@@ -297,7 +297,7 @@ module Capybara
|
|
|
297
297
|
|
|
298
298
|
##
|
|
299
299
|
#
|
|
300
|
-
# The current Capybara::Session based on what is set as
|
|
300
|
+
# The current {Capybara::Session} based on what is set as {app} and {current_driver}.
|
|
301
301
|
#
|
|
302
302
|
# @return [Capybara::Session] The currently used session
|
|
303
303
|
#
|
|
@@ -340,7 +340,7 @@ module Capybara
|
|
|
340
340
|
|
|
341
341
|
##
|
|
342
342
|
#
|
|
343
|
-
# Yield a block using a specific session name or Capybara::Session instance.
|
|
343
|
+
# Yield a block using a specific session name or {Capybara::Session} instance.
|
|
344
344
|
#
|
|
345
345
|
def using_session(name_or_session)
|
|
346
346
|
previous_session_info = {
|
|
@@ -64,6 +64,8 @@ Capybara::SpecHelper.run_specs TestSessions::SeleniumFirefox, 'selenium', capyba
|
|
|
64
64
|
pending "Geckodriver doesn't provide a way to remove cookies outside the current domain"
|
|
65
65
|
when 'Capybara::Session selenium #attach_file with a block can upload by clicking the file input'
|
|
66
66
|
pending "Geckodriver doesn't allow clicking on file inputs"
|
|
67
|
+
when /drag_to.*HTML5/
|
|
68
|
+
pending "Firefox < 62 doesn't support a DataTransfer constuctor" if firefox_lt?(62.0, @session)
|
|
67
69
|
end
|
|
68
70
|
end
|
|
69
71
|
|
data/spec/selenium_spec_ie.rb
CHANGED
|
@@ -6,13 +6,13 @@ require 'shared_selenium_session'
|
|
|
6
6
|
require 'shared_selenium_node'
|
|
7
7
|
require 'rspec/shared_spec_matchers'
|
|
8
8
|
|
|
9
|
-
if ENV['CI']
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
end
|
|
9
|
+
# if ENV['CI']
|
|
10
|
+
# if ::Selenium::WebDriver::Service.respond_to? :driver_path=
|
|
11
|
+
# ::Selenium::WebDriver::IE::Service
|
|
12
|
+
# else
|
|
13
|
+
# ::Selenium::WebDriver::IE
|
|
14
|
+
# end.driver_path = 'C:\Tools\WebDriver\IEDriverServer.exe'
|
|
15
|
+
# end
|
|
16
16
|
|
|
17
17
|
def selenium_host
|
|
18
18
|
ENV.fetch('SELENIUM_HOST', '192.168.56.102')
|
|
@@ -110,6 +110,12 @@ Capybara::SpecHelper.run_specs TestSessions::SeleniumIE, 'selenium', capybara_sk
|
|
|
110
110
|
pending 'IE treats blank href as a parent request (against HTML spec)'
|
|
111
111
|
when /#attach_file with a block/
|
|
112
112
|
skip 'Hangs IE testing for unknown reason'
|
|
113
|
+
when /drag_to.*HTML5/
|
|
114
|
+
pending "IE doesn't support a DataTransfer constuctor"
|
|
115
|
+
when /template elements should not be visible/
|
|
116
|
+
skip "IE doesn't support template elements"
|
|
117
|
+
when /Element#drop/
|
|
118
|
+
pending "IE doesn't support DataTransfer constructor"
|
|
113
119
|
end
|
|
114
120
|
end
|
|
115
121
|
|
|
@@ -73,6 +73,8 @@ Capybara::SpecHelper.run_specs TestSessions::Safari, SAFARI_DRIVER.to_s, capybar
|
|
|
73
73
|
when 'Capybara::Session selenium_safari #go_back should fetch a response from the driver from the previous page',
|
|
74
74
|
'Capybara::Session selenium_safari #go_forward should fetch a response from the driver from the previous page'
|
|
75
75
|
skip 'safaridriver loses the ability to find elements in the document after `go_back`'
|
|
76
|
+
when /drag_to.*HTML5/
|
|
77
|
+
pending "Safari doesn't support"
|
|
76
78
|
end
|
|
77
79
|
end
|
|
78
80
|
|
|
@@ -303,57 +303,6 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
|
303
303
|
end
|
|
304
304
|
end
|
|
305
305
|
|
|
306
|
-
describe 'Element#drag_to' do
|
|
307
|
-
before do
|
|
308
|
-
skip "Firefox < 62 doesn't support a DataTransfer constuctor" if firefox_lt?(62.0, session)
|
|
309
|
-
skip "IE doesn't support a DataTransfer constuctor" if ie?(session)
|
|
310
|
-
skip "Safari doesn't support" if safari?(session)
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
it 'should HTML5 drag and drop an object' do
|
|
314
|
-
session.visit('/with_js')
|
|
315
|
-
element = session.find('//div[@id="drag_html5"]')
|
|
316
|
-
target = session.find('//div[@id="drop_html5"]')
|
|
317
|
-
element.drag_to(target)
|
|
318
|
-
expect(session).to have_xpath('//div[contains(., "HTML5 Dropped drag_html5")]')
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
it 'should set clientX/Y in dragover events' do
|
|
322
|
-
session.visit('/with_js')
|
|
323
|
-
element = session.find('//div[@id="drag_html5"]')
|
|
324
|
-
target = session.find('//div[@id="drop_html5"]')
|
|
325
|
-
element.drag_to(target)
|
|
326
|
-
session.all(:css, 'div.log').each { |el| puts el.text }
|
|
327
|
-
expect(session).to have_css('div.log', text: /DragOver with client position: [1-9]\d*,[1-9]\d*/, count: 2)
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
it 'should not HTML5 drag and drop on a non HTML5 drop element' do
|
|
331
|
-
session.visit('/with_js')
|
|
332
|
-
element = session.find('//div[@id="drag_html5"]')
|
|
333
|
-
target = session.find('//div[@id="drop_html5"]')
|
|
334
|
-
target.execute_script("$(this).removeClass('drop');")
|
|
335
|
-
element.drag_to(target)
|
|
336
|
-
sleep 1
|
|
337
|
-
expect(session).not_to have_xpath('//div[contains(., "HTML5 Dropped drag_html5")]')
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
it 'should HTML5 drag and drop when scrolling needed' do
|
|
341
|
-
session.visit('/with_js')
|
|
342
|
-
element = session.find('//div[@id="drag_html5_scroll"]')
|
|
343
|
-
target = session.find('//div[@id="drop_html5_scroll"]')
|
|
344
|
-
element.drag_to(target)
|
|
345
|
-
expect(session).to have_xpath('//div[contains(., "HTML5 Dropped drag_html5_scroll")]')
|
|
346
|
-
end
|
|
347
|
-
|
|
348
|
-
it 'should drag HTML5 default draggable elements' do
|
|
349
|
-
session.visit('/with_js')
|
|
350
|
-
link = session.find_link('drag_link_html5')
|
|
351
|
-
target = session.find(:id, 'drop_html5')
|
|
352
|
-
link.drag_to target
|
|
353
|
-
expect(session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
|
|
354
|
-
end
|
|
355
|
-
end
|
|
356
|
-
|
|
357
306
|
describe 'Capybara#Node#attach_file' do
|
|
358
307
|
it 'can attach a directory' do
|
|
359
308
|
pending "Geckodriver doesn't support uploading a directory" if firefox?(session)
|
|
@@ -472,6 +421,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
|
472
421
|
describe 'with react' do
|
|
473
422
|
context 'controlled components' do
|
|
474
423
|
it 'can set and clear a text field' do
|
|
424
|
+
skip "This test doesn't support older browsers" if ie?(session)
|
|
475
425
|
# session.visit 'https://reactjs.org/docs/forms.html'
|
|
476
426
|
# session.all(:css, 'h2#controlled-components ~ p a', text: 'Try it on CodePen')[0].click
|
|
477
427
|
# copied into local view
|