capybara 3.7.0 → 3.8.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 +28 -1
- data/README.md +1 -1
- data/lib/capybara/helpers.rb +1 -0
- data/lib/capybara/node/actions.rb +22 -2
- data/lib/capybara/node/base.rb +0 -1
- data/lib/capybara/node/finders.rb +4 -0
- data/lib/capybara/node/matchers.rb +1 -1
- data/lib/capybara/selector/css.rb +1 -1
- data/lib/capybara/selector.rb +1 -1
- data/lib/capybara/selenium/driver.rb +3 -4
- data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +9 -0
- data/lib/capybara/selenium/extensions/html5_drag.rb +59 -0
- data/lib/capybara/selenium/nodes/chrome_node.rb +6 -26
- data/lib/capybara/selenium/nodes/marionette_node.rb +6 -26
- data/lib/capybara/selenium/patches/pause_duration_fix.rb +11 -0
- data/lib/capybara/server/checker.rb +3 -1
- data/lib/capybara/session.rb +1 -1
- data/lib/capybara/spec/public/test.js +1 -1
- data/lib/capybara/spec/session/assert_selector_spec.rb +1 -1
- data/lib/capybara/spec/session/current_url_spec.rb +1 -1
- data/lib/capybara/spec/session/element/match_css_spec.rb +6 -0
- data/lib/capybara/spec/session/has_css_spec.rb +7 -0
- data/lib/capybara/spec/session/node_spec.rb +8 -0
- data/lib/capybara/spec/session/window/window_spec.rb +2 -4
- data/lib/capybara/spec/views/with_html5_svg.erb +20 -0
- data/lib/capybara/spec/views/with_js.erb +2 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +4 -6
- data/lib/capybara.rb +4 -1
- data/spec/dsl_spec.rb +2 -8
- data/spec/selenium_spec_chrome.rb +6 -1
- data/spec/selenium_spec_firefox_remote.rb +6 -6
- data/spec/selenium_spec_marionette.rb +5 -1
- data/spec/shared_selenium_session.rb +32 -3
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 814367062843328d421eb8c9db0476cabe5a16405866951855507dd63250bfb9
|
|
4
|
+
data.tar.gz: 2b6605e124b8eed5d4efbc7f2e06d56dcf2ddaa8775d2ec7f42b18aca4144f3a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 76d6d964d8e204497e9f57b61e96ecf32631325c6c4b600ead18009817f45e324f241520d134881bfa62bba754d820f5e1d91710e4c78ca98ccdd06325a206fb
|
|
7
|
+
data.tar.gz: ee215bc20878dcce34e1df44f2081e3867528358bd1c7cae542b5996e945ca1f6c16decba834ec3c13bd46052873c6988ef7c141674648eae8f5894fec405f38
|
data/History.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
# Version 3.8.0
|
|
2
|
+
Release date: 2018-09-20
|
|
3
|
+
|
|
4
|
+
### Added
|
|
5
|
+
|
|
6
|
+
* Workaround gecodriver 0.22 issue with undefined pause durations
|
|
7
|
+
* :element selector ignores XML namespaces
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
* Added Errno::ECONNRESET to the errors which will allows https server detection
|
|
12
|
+
|
|
13
|
+
# Version 3.7.2
|
|
14
|
+
Release date: 2018-09-12
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
* Fix MatchQuery based matchers when used on a root element found using any type of parent/ancestor query - Issue #2097
|
|
19
|
+
|
|
20
|
+
* Fix Chrome/FF HTML5 drag simulation for elements (a, img) which default to draggable - Issue #2098
|
|
21
|
+
|
|
22
|
+
# Version 3.7.1
|
|
23
|
+
Release date: 2018-09-05
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
* Restored ability to pass symbol as the CSS selector when calling `has_css?`/`have_css`/etc - Issue #2093
|
|
28
|
+
|
|
1
29
|
# Version 3.7.0
|
|
2
30
|
Release date: 2018-09-02
|
|
3
31
|
|
|
@@ -12,7 +40,6 @@ Release date: 2018-09-02
|
|
|
12
40
|
|
|
13
41
|
* All CSS styles applied by the `Element#attach_file` `:make_visible` option will now have `!important` priority set to ensure they override any other specified style.
|
|
14
42
|
* Firefox file inputs are only manually cleared when necessary.
|
|
15
|
-
*
|
|
16
43
|
|
|
17
44
|
# Version 3.6.0
|
|
18
45
|
Release date: 2018-08-14
|
data/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://dependabot.com/compatibility-score.html?dependency-name=capybara&package-manager=bundler&version-scheme=semver)
|
|
8
8
|
|
|
9
9
|
**Note** You are viewing the README for the development version of Capybara. If you are using the current release version
|
|
10
|
-
you can find the README at https://github.com/teamcapybara/capybara/blob/3.
|
|
10
|
+
you can find the README at https://github.com/teamcapybara/capybara/blob/3.8_stable/README.md
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
Capybara helps you test web applications by simulating how a real user would
|
data/lib/capybara/helpers.rb
CHANGED
|
@@ -64,8 +64,12 @@ module Capybara
|
|
|
64
64
|
# The field can be found via its name, id, Capybara.test_id attribute, or label text.
|
|
65
65
|
# If no locator is provided will operate on self or a descendant
|
|
66
66
|
#
|
|
67
|
+
# # will fill in a descendant fillable field with name, id, or label text matching 'Name'
|
|
67
68
|
# page.fill_in 'Name', with: 'Bob'
|
|
68
69
|
#
|
|
70
|
+
# # will fill in `el` if it's a fillable field
|
|
71
|
+
# el.fill_in with: 'Tom'
|
|
72
|
+
#
|
|
69
73
|
#
|
|
70
74
|
# @overload fill_in([locator], with:, **options)
|
|
71
75
|
# @param [String] locator Which field to fill in
|
|
@@ -96,8 +100,12 @@ module Capybara
|
|
|
96
100
|
# via name, id or label text. If no locator is provided this will match against self or
|
|
97
101
|
# a descendant.
|
|
98
102
|
#
|
|
103
|
+
# # will choose a descendant radio button with a name, id, or label text matching 'Male'
|
|
99
104
|
# page.choose('Male')
|
|
100
105
|
#
|
|
106
|
+
# # will choose `el` if it's a radio button element
|
|
107
|
+
# el.choose()
|
|
108
|
+
#
|
|
101
109
|
# @overload choose([locator], **options)
|
|
102
110
|
# @param [String] locator Which radio button to choose
|
|
103
111
|
#
|
|
@@ -119,8 +127,12 @@ module Capybara
|
|
|
119
127
|
# via name, id or label text. If no locator is provided this will match against
|
|
120
128
|
# self or a descendant.
|
|
121
129
|
#
|
|
130
|
+
# # will check a descendant checkbox with a name, id, or label text matching 'German'
|
|
122
131
|
# page.check('German')
|
|
123
132
|
#
|
|
133
|
+
# # will check `el` if it's a checkbox element
|
|
134
|
+
# el.check()
|
|
135
|
+
#
|
|
124
136
|
#
|
|
125
137
|
# @overload check([locator], **options)
|
|
126
138
|
# @param [String] locator Which check box to check
|
|
@@ -139,12 +151,16 @@ module Capybara
|
|
|
139
151
|
|
|
140
152
|
##
|
|
141
153
|
#
|
|
142
|
-
# Find a descendant check box and
|
|
154
|
+
# Find a descendant check box and uncheck it. The check box can be found
|
|
143
155
|
# via name, id or label text. If no locator is provided this will match against
|
|
144
156
|
# self or a descendant.
|
|
145
157
|
#
|
|
158
|
+
# # will uncheck a descendant checkbox with a name, id, or label text matching 'German'
|
|
146
159
|
# page.uncheck('German')
|
|
147
160
|
#
|
|
161
|
+
# # will uncheck `el` if it's a checkbox element
|
|
162
|
+
# el.uncheck()
|
|
163
|
+
#
|
|
148
164
|
#
|
|
149
165
|
# @overload uncheck([locator], **options)
|
|
150
166
|
# @param [String] locator Which check box to uncheck
|
|
@@ -215,7 +231,11 @@ module Capybara
|
|
|
215
231
|
# the file field, attach the file, and then revert the CSS back to original. If no locator is
|
|
216
232
|
# passed this will match self or a descendant.
|
|
217
233
|
#
|
|
218
|
-
#
|
|
234
|
+
# # will attach file to a descendant file input element that has a name, id, or label_text matching 'My File'
|
|
235
|
+
# page.attach_file('My File', '/path/to/file.png')
|
|
236
|
+
#
|
|
237
|
+
# # will attach file to el if it's a file input element
|
|
238
|
+
# el.attach_file('/path/to/file.png')
|
|
219
239
|
#
|
|
220
240
|
# @overload attach_file([locator], paths, **options)
|
|
221
241
|
# @macro waiting_behavior
|
data/lib/capybara/node/base.rb
CHANGED
|
@@ -85,7 +85,6 @@ module Capybara
|
|
|
85
85
|
raise err unless driver.wait? && catch_error?(err, errors)
|
|
86
86
|
raise err if timer.expired?
|
|
87
87
|
sleep(0.05)
|
|
88
|
-
raise Capybara::FrozenInTime, 'Time appears to be frozen. Capybara does not work with libraries which freeze time, consider using time travelling instead' if timer.stalled?
|
|
89
88
|
reload if session_options.automatic_reload
|
|
90
89
|
retry
|
|
91
90
|
ensure
|
|
@@ -713,7 +713,7 @@ module Capybara
|
|
|
713
713
|
query_args = _set_query_session_options(*query_args)
|
|
714
714
|
query = Capybara::Queries::MatchQuery.new(*query_args, &optional_filter_block)
|
|
715
715
|
synchronize(query.wait) do
|
|
716
|
-
yield query.resolve_for(
|
|
716
|
+
yield query.resolve_for(parent || session&.document || query_scope)
|
|
717
717
|
end
|
|
718
718
|
true
|
|
719
719
|
end
|
data/lib/capybara/selector.rb
CHANGED
|
@@ -468,7 +468,7 @@ end
|
|
|
468
468
|
|
|
469
469
|
Capybara.add_selector(:element) do
|
|
470
470
|
xpath do |locator, **|
|
|
471
|
-
locator ? XPath.
|
|
471
|
+
XPath.descendant.where(locator ? XPath.local_name == locator.to_s : nil)
|
|
472
472
|
end
|
|
473
473
|
|
|
474
474
|
expression_filter(:attributes, matcher: /.+/) do |xpath, name, val|
|
|
@@ -28,6 +28,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
28
28
|
setup_exit_handler
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
|
+
@browser
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
def initialize(app, **options)
|
|
@@ -143,11 +144,8 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
143
144
|
handles.clear
|
|
144
145
|
browser.switch_to.default_content
|
|
145
146
|
when :parent
|
|
146
|
-
# would love to use browser.switch_to.parent_frame here
|
|
147
|
-
# but it has an issue if the current frame is removed from within it
|
|
148
147
|
handles.pop
|
|
149
|
-
browser.switch_to.
|
|
150
|
-
handles.each { |fh| browser.switch_to.frame(fh) }
|
|
148
|
+
browser.switch_to.parent_frame
|
|
151
149
|
else
|
|
152
150
|
handles << frame.native
|
|
153
151
|
browser.switch_to.frame(frame.native)
|
|
@@ -363,6 +361,7 @@ private
|
|
|
363
361
|
when :chrome
|
|
364
362
|
extend ChromeDriver
|
|
365
363
|
when :firefox
|
|
364
|
+
require 'capybara/selenium/patches/pause_duration_fix' if sel_driver.capabilities['moz:geckodriverVersion']&.start_with?('0.22.')
|
|
366
365
|
extend MarionetteDriver if sel_driver.capabilities.is_a?(::Selenium::WebDriver::Remote::W3C::Capabilities)
|
|
367
366
|
end
|
|
368
367
|
end
|
|
@@ -32,6 +32,15 @@ module Capybara::Selenium::Driver::MarionetteDriver
|
|
|
32
32
|
# No modal was opened - page has refreshed - ignore
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
def switch_to_frame(frame)
|
|
36
|
+
return super unless frame == :parent
|
|
37
|
+
# geckodriver/firefox has an issue if the current frame is removed from within it
|
|
38
|
+
# so we have to move to the default_content and iterate back through the frames
|
|
39
|
+
handles = @frame_handles[current_window_handle]
|
|
40
|
+
browser.switch_to.default_content
|
|
41
|
+
handles.tap(&:pop).each { |fh| browser.switch_to.frame(fh) }
|
|
42
|
+
end
|
|
43
|
+
|
|
35
44
|
private
|
|
36
45
|
|
|
37
46
|
def build_node(native_node)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Capybara::Selenium::Node
|
|
4
|
+
module Html5Drag
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
def html5_drag_to(element)
|
|
8
|
+
driver.execute_script MOUSEDOWN_TRACKER
|
|
9
|
+
scroll_if_needed { browser_action.click_and_hold(native).perform }
|
|
10
|
+
if driver.evaluate_script('window.capybara_mousedown_prevented')
|
|
11
|
+
element.scroll_if_needed { browser_action.move_to(element.native).release.perform }
|
|
12
|
+
else
|
|
13
|
+
driver.execute_script HTML5_DRAG_DROP_SCRIPT, self, element
|
|
14
|
+
browser_action.release.perform
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def html5_draggable?
|
|
19
|
+
# Workaround https://github.com/SeleniumHQ/selenium/issues/6396
|
|
20
|
+
native.property('draggable')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
MOUSEDOWN_TRACKER = <<~JS
|
|
24
|
+
document.addEventListener('mousedown', ev => {
|
|
25
|
+
window.capybara_mousedown_prevented = ev.defaultPrevented;
|
|
26
|
+
}, { once: true, passive: true })
|
|
27
|
+
JS
|
|
28
|
+
|
|
29
|
+
HTML5_DRAG_DROP_SCRIPT = <<~JS
|
|
30
|
+
var source = arguments[0];
|
|
31
|
+
var target = arguments[1];
|
|
32
|
+
|
|
33
|
+
var dt = new DataTransfer();
|
|
34
|
+
var opts = { cancelable: true, bubbles: true, dataTransfer: dt };
|
|
35
|
+
|
|
36
|
+
if (source.tagName == 'A'){
|
|
37
|
+
dt.setData('text/uri-list', source.href);
|
|
38
|
+
dt.setData('text', source.href);
|
|
39
|
+
}
|
|
40
|
+
if (source.tagName == 'IMG'){
|
|
41
|
+
dt.setData('text/uri-list', source.src);
|
|
42
|
+
dt.setData('text', source.src);
|
|
43
|
+
}
|
|
44
|
+
var dragEvent = new DragEvent('dragstart', opts);
|
|
45
|
+
source.dispatchEvent(dragEvent);
|
|
46
|
+
target.scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'});
|
|
47
|
+
var dragOverEvent = new DragEvent('dragover', opts);
|
|
48
|
+
target.dispatchEvent(dragOverEvent);
|
|
49
|
+
var dragLeaveEvent = new DragEvent('dragleave', opts);
|
|
50
|
+
target.dispatchEvent(dragLeaveEvent);
|
|
51
|
+
if (dragOverEvent.defaultPrevented) {
|
|
52
|
+
var dropEvent = new DragEvent('drop', opts);
|
|
53
|
+
target.dispatchEvent(dropEvent);
|
|
54
|
+
}
|
|
55
|
+
var dragEndEvent = new DragEvent('dragend', opts);
|
|
56
|
+
source.dispatchEvent(dragEndEvent);
|
|
57
|
+
JS
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'capybara/selenium/extensions/html5_drag'
|
|
4
|
+
|
|
3
5
|
class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
|
|
6
|
+
include Html5Drag
|
|
7
|
+
|
|
4
8
|
def set_file(value) # rubocop:disable Naming/AccessorMethodName
|
|
5
9
|
super(value)
|
|
6
10
|
rescue ::Selenium::WebDriver::Error::ExpectedError => err
|
|
@@ -11,10 +15,8 @@ class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
|
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
def drag_to(element)
|
|
14
|
-
return super unless
|
|
15
|
-
|
|
16
|
-
scroll_if_needed { browser_action.click_and_hold(native).perform }
|
|
17
|
-
driver.execute_script HTML5_DRAG_DROP_SCRIPT, self, element
|
|
18
|
+
return super unless html5_draggable?
|
|
19
|
+
html5_drag_to(element)
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
private
|
|
@@ -22,26 +24,4 @@ private
|
|
|
22
24
|
def bridge
|
|
23
25
|
driver.browser.send(:bridge)
|
|
24
26
|
end
|
|
25
|
-
|
|
26
|
-
HTML5_DRAG_DROP_SCRIPT = <<~JS
|
|
27
|
-
var source = arguments[0];
|
|
28
|
-
var target = arguments[1];
|
|
29
|
-
|
|
30
|
-
var dt = new DataTransfer();
|
|
31
|
-
var opts = { cancelable: true, bubbles: true, dataTransfer: dt };
|
|
32
|
-
|
|
33
|
-
var dragEvent = new DragEvent('dragstart', opts);
|
|
34
|
-
source.dispatchEvent(dragEvent);
|
|
35
|
-
target.scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'});
|
|
36
|
-
var dragOverEvent = new DragEvent('dragover', opts);
|
|
37
|
-
target.dispatchEvent(dragOverEvent);
|
|
38
|
-
var dragLeaveEvent = new DragEvent('dragleave', opts);
|
|
39
|
-
target.dispatchEvent(dragLeaveEvent);
|
|
40
|
-
if (dragOverEvent.defaultPrevented) {
|
|
41
|
-
var dropEvent = new DragEvent('drop', opts);
|
|
42
|
-
target.dispatchEvent(dropEvent);
|
|
43
|
-
}
|
|
44
|
-
var dragEndEvent = new DragEvent('dragend', opts);
|
|
45
|
-
source.dispatchEvent(dragEndEvent);
|
|
46
|
-
JS
|
|
47
27
|
end
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'capybara/selenium/extensions/html5_drag'
|
|
4
|
+
|
|
3
5
|
class Capybara::Selenium::MarionetteNode < Capybara::Selenium::Node
|
|
6
|
+
include Html5Drag
|
|
7
|
+
|
|
4
8
|
def click(keys = [], **options)
|
|
5
9
|
super
|
|
6
10
|
rescue ::Selenium::WebDriver::Error::ElementNotInteractableError
|
|
@@ -54,10 +58,8 @@ class Capybara::Selenium::MarionetteNode < Capybara::Selenium::Node
|
|
|
54
58
|
end
|
|
55
59
|
|
|
56
60
|
def drag_to(element)
|
|
57
|
-
return super unless (browser_version >= 62.0) &&
|
|
58
|
-
|
|
59
|
-
scroll_if_needed { browser_action.click_and_hold(native).perform }
|
|
60
|
-
driver.execute_script HTML5_DRAG_DROP_SCRIPT, self, element
|
|
61
|
+
return super unless (browser_version >= 62.0) && html5_draggable?
|
|
62
|
+
html5_drag_to(element)
|
|
61
63
|
end
|
|
62
64
|
|
|
63
65
|
private
|
|
@@ -116,26 +118,4 @@ private
|
|
|
116
118
|
def browser_version
|
|
117
119
|
driver.browser.capabilities[:browser_version].to_f
|
|
118
120
|
end
|
|
119
|
-
|
|
120
|
-
HTML5_DRAG_DROP_SCRIPT = <<~JS
|
|
121
|
-
var source = arguments[0];
|
|
122
|
-
var target = arguments[1];
|
|
123
|
-
|
|
124
|
-
var dt = new DataTransfer();
|
|
125
|
-
var opts = { cancelable: true, bubbles: true, dataTransfer: dt };
|
|
126
|
-
|
|
127
|
-
var dragEvent = new DragEvent('dragstart', opts);
|
|
128
|
-
source.dispatchEvent(dragEvent);
|
|
129
|
-
target.scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'});
|
|
130
|
-
var dragOverEvent = new DragEvent('dragover', opts);
|
|
131
|
-
target.dispatchEvent(dragOverEvent);
|
|
132
|
-
var dragLeaveEvent = new DragEvent('dragleave', opts);
|
|
133
|
-
target.dispatchEvent(dragLeaveEvent);
|
|
134
|
-
if (dragOverEvent.defaultPrevented) {
|
|
135
|
-
var dropEvent = new DragEvent('drop', opts);
|
|
136
|
-
target.dispatchEvent(dropEvent);
|
|
137
|
-
}
|
|
138
|
-
var dragEndEvent = new DragEvent('dragend', opts);
|
|
139
|
-
source.dispatchEvent(dragEndEvent);
|
|
140
|
-
JS
|
|
141
121
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PauseDurationFix
|
|
4
|
+
def encode
|
|
5
|
+
super.tap { |output| output[:duration] ||= 0 }
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
if defined?(::Selenium::WebDriver::Interactions::Pause)
|
|
10
|
+
::Selenium::WebDriver::Interactions::Pause.prepend PauseDurationFix
|
|
11
|
+
end
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
module Capybara
|
|
4
4
|
class Server
|
|
5
5
|
class Checker
|
|
6
|
+
TRY_HTTPS_ERRORS = [EOFError, Net::ReadTimeout, Errno::ECONNRESET].freeze
|
|
7
|
+
|
|
6
8
|
def initialize(host, port)
|
|
7
9
|
@host, @port = host, port
|
|
8
10
|
@ssl = false
|
|
@@ -10,7 +12,7 @@ module Capybara
|
|
|
10
12
|
|
|
11
13
|
def request(&block)
|
|
12
14
|
ssl? ? https_request(&block) : http_request(&block)
|
|
13
|
-
rescue
|
|
15
|
+
rescue *TRY_HTTPS_ERRORS
|
|
14
16
|
res = https_request(&block)
|
|
15
17
|
@ssl = true
|
|
16
18
|
res
|
data/lib/capybara/session.rb
CHANGED
|
@@ -364,7 +364,7 @@ module Capybara
|
|
|
364
364
|
# @overload switch_to_frame(element)
|
|
365
365
|
# @param [Capybara::Node::Element] iframe/frame element to switch to
|
|
366
366
|
# @overload switch_to_frame(:parent)
|
|
367
|
-
# Switch to the parent
|
|
367
|
+
# Switch to the parent frame
|
|
368
368
|
# @overload switch_to_frame(:top)
|
|
369
369
|
# Switch to the top level document
|
|
370
370
|
#
|
|
@@ -72,7 +72,7 @@ Capybara::SpecHelper.spec '#assert_selector' do
|
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
Capybara::SpecHelper.spec '#refute_selector' do
|
|
75
|
+
Capybara::SpecHelper.spec '#refute_selector', requires: [:driver] do
|
|
76
76
|
it 'should warn not to use' do
|
|
77
77
|
@session.visit('/with_html')
|
|
78
78
|
doc = @session.document
|
|
@@ -96,7 +96,7 @@ Capybara::SpecHelper.spec '#current_url, #current_path, #current_host' do
|
|
|
96
96
|
expect(@session.current_path).to eq('/replaced')
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
-
it "doesn't raise exception on a nil current_url" do
|
|
99
|
+
it "doesn't raise exception on a nil current_url", requires: [:driver] do
|
|
100
100
|
allow(@session.driver).to receive(:current_url).and_return(nil)
|
|
101
101
|
@session.visit('/')
|
|
102
102
|
expect { @session.current_url }.not_to raise_exception
|
|
@@ -22,4 +22,10 @@ Capybara::SpecHelper.spec '#match_css?' do
|
|
|
22
22
|
expect(@element).to match_css('span') { |el| el[:class] == 'number' }
|
|
23
23
|
expect(@element).not_to match_css('span') { |el| el[:class] == 'not_number' }
|
|
24
24
|
end
|
|
25
|
+
|
|
26
|
+
it 'should work with root element found via ancestor' do
|
|
27
|
+
el = @session.find(:css, 'body').find(:xpath, '..')
|
|
28
|
+
expect(el).to match_css('html')
|
|
29
|
+
expect { expect(el).to not_match_css('html') }.to raise_exception(RSpec::Expectations::ExpectationNotMetError)
|
|
30
|
+
end
|
|
25
31
|
end
|
|
@@ -10,6 +10,13 @@ Capybara::SpecHelper.spec '#has_css?' do
|
|
|
10
10
|
expect(@session).to have_css('p a#foo')
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
it 'should take a symbol as the selector' do
|
|
14
|
+
# This was never a specifically accepted format but it has worked for a
|
|
15
|
+
# lot of versions. Probably should keep it until at least 4.0
|
|
16
|
+
# TODO: consider not supporting symbol for the CSS selector.
|
|
17
|
+
expect(@session).to have_css(:p)
|
|
18
|
+
end
|
|
19
|
+
|
|
13
20
|
it 'should be false if the given selector is not on the page' do
|
|
14
21
|
expect(@session).not_to have_css('abbr')
|
|
15
22
|
expect(@session).not_to have_css('p a#doesnotexist')
|
|
@@ -316,6 +316,14 @@ Capybara::SpecHelper.spec 'node' do
|
|
|
316
316
|
element.drag_to(target)
|
|
317
317
|
expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
|
|
318
318
|
end
|
|
319
|
+
|
|
320
|
+
it 'should drag a link' do
|
|
321
|
+
@session.visit('/with_js')
|
|
322
|
+
link = @session.find_link('drag_link')
|
|
323
|
+
target = @session.find(:id, 'drop')
|
|
324
|
+
link.drag_to target
|
|
325
|
+
expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
|
|
326
|
+
end
|
|
319
327
|
end
|
|
320
328
|
|
|
321
329
|
describe '#hover', requires: [:hover] do
|
|
@@ -130,13 +130,11 @@ Capybara::SpecHelper.spec Capybara::Window, requires: [:windows] do
|
|
|
130
130
|
@other_window = @session.window_opened_by do
|
|
131
131
|
@session.find(:css, '#openWindow').click
|
|
132
132
|
end
|
|
133
|
-
@other_window.resize_to(
|
|
133
|
+
@other_window.resize_to(600, 300)
|
|
134
134
|
expect(@session.current_window).to eq(@window)
|
|
135
135
|
|
|
136
|
-
# #size returns values larger than availWidth, availHeight with Chromedriver
|
|
137
136
|
@session.within_window(@other_window) do
|
|
138
|
-
expect(@session.current_window.size).to eq([
|
|
139
|
-
# expect(@session.evaluate_script("[window.outerWidth, window.outerHeight]")).to eq([400,300])
|
|
137
|
+
expect(@session.current_window.size).to eq([600, 300])
|
|
140
138
|
end
|
|
141
139
|
end
|
|
142
140
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Namespace</title>
|
|
5
|
+
</head>
|
|
6
|
+
<body id="body">
|
|
7
|
+
<div>
|
|
8
|
+
<svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice"
|
|
9
|
+
style="width:100%; height:100%; position:absolute; top:0; left:0; z-index:-1;">
|
|
10
|
+
<linearGradient id="gradient">
|
|
11
|
+
<stop class="begin" offset="0%"/>
|
|
12
|
+
<stop class="end" offset="100%"/>
|
|
13
|
+
</linearGradient>
|
|
14
|
+
<rect x="0" y="0" width="100" height="100" style="fill:url(#gradient)" />
|
|
15
|
+
<rect x="150" y="150" width="25" height="25" style="fill:url(#gradient)" />
|
|
16
|
+
<circle cx="50" cy="50" r="30" style="fill:url(#gradient)" />
|
|
17
|
+
</svg>
|
|
18
|
+
<div>
|
|
19
|
+
</body>
|
|
20
|
+
</html>
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
<h1>FooBar</h1>
|
|
13
13
|
|
|
14
14
|
<p id="change">This is text</p>
|
|
15
|
+
<a id="drag_link" href='#'>This link is non-HTML5 draggable</a>
|
|
15
16
|
<div id="drag">
|
|
16
17
|
<p>This is a draggable element.</p>
|
|
17
18
|
</div>
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
<div id="drag_html5" draggable="true">
|
|
28
29
|
<p>This is an HTML5 draggable element.</p>
|
|
29
30
|
</div>
|
|
31
|
+
<a id="drag_link_html5" href="#">This is an HTML5 draggable link</a>
|
|
30
32
|
<div id="drop_html5" class="drop">
|
|
31
33
|
<p>It should be dropped here.</p>
|
|
32
34
|
</div>
|
data/lib/capybara/version.rb
CHANGED
data/lib/capybara/window.rb
CHANGED
|
@@ -129,14 +129,12 @@ module Capybara
|
|
|
129
129
|
|
|
130
130
|
def wait_for_stable_size(seconds = session.config.default_max_wait_time)
|
|
131
131
|
res = yield if block_given?
|
|
132
|
-
|
|
133
|
-
start_time = Capybara::Helpers.monotonic_time
|
|
132
|
+
timer = Capybara::Helpers.timer(expire_in: seconds)
|
|
134
133
|
loop do
|
|
134
|
+
prev_size = size
|
|
135
135
|
sleep 0.05
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
prev_size = cur_size
|
|
139
|
-
break if (Capybara::Helpers.monotonic_time - start_time) >= seconds
|
|
136
|
+
return res if prev_size == size
|
|
137
|
+
break if timer.expired?
|
|
140
138
|
end
|
|
141
139
|
raise Capybara::WindowError, "Window size not stable within #{seconds} seconds."
|
|
142
140
|
end
|
data/lib/capybara.rb
CHANGED
|
@@ -430,7 +430,6 @@ module Capybara
|
|
|
430
430
|
require 'capybara/rack_test/css_handlers.rb'
|
|
431
431
|
|
|
432
432
|
require 'capybara/selenium/node'
|
|
433
|
-
require 'capybara/selenium/nodes/marionette_node'
|
|
434
433
|
require 'capybara/selenium/driver'
|
|
435
434
|
end
|
|
436
435
|
|
|
@@ -448,6 +447,10 @@ Capybara.register_server :puma do |app, port, host, **options|
|
|
|
448
447
|
require 'rack/handler/puma'
|
|
449
448
|
rescue LoadError
|
|
450
449
|
raise LoadError, 'Capybara is unable to load `puma` for its server, please add `puma` to your project or specify a different server via something like `Capybara.server = :webrick`.'
|
|
450
|
+
else
|
|
451
|
+
unless Rack::Handler::Puma.respond_to?(:config)
|
|
452
|
+
raise LoadError, 'Capybara requires `puma` version 3.8.0 or higher, please upgrade `puma` or register and specify your own server block'
|
|
453
|
+
end
|
|
451
454
|
end
|
|
452
455
|
# If we just run the Puma Rack handler it installs signal handlers which prevent us from being able to interrupt tests.
|
|
453
456
|
# Therefore construct and run the Server instance ourselves.
|
data/spec/dsl_spec.rb
CHANGED
|
@@ -8,14 +8,8 @@ class TestClass
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
Capybara::SpecHelper.run_specs TestClass.new, 'DSL', capybara_skip: %i[
|
|
11
|
-
js modals screenshot frames windows send_keys server hover about_scheme psc download css
|
|
12
|
-
]
|
|
13
|
-
case example.metadata[:full_description]
|
|
14
|
-
when /doesn't raise exception on a nil current_url$/,
|
|
15
|
-
/#refute_selector should warn not to use$/
|
|
16
|
-
skip 'Only makes sense when there is a real driver'
|
|
17
|
-
end
|
|
18
|
-
end
|
|
11
|
+
js modals screenshot frames windows send_keys server hover about_scheme psc download css driver
|
|
12
|
+
]
|
|
19
13
|
|
|
20
14
|
RSpec.describe Capybara::DSL do
|
|
21
15
|
after do
|
|
@@ -45,7 +45,12 @@ skipped_tests << :windows if ENV['TRAVIS'] && (ENV['SKIP_WINDOW'] || ENV['HEADLE
|
|
|
45
45
|
|
|
46
46
|
$stdout.puts `#{Selenium::WebDriver::Chrome.driver_path} --version` if ENV['CI']
|
|
47
47
|
|
|
48
|
-
Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_DRIVER.to_s, capybara_skip: skipped_tests
|
|
48
|
+
Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_DRIVER.to_s, capybara_skip: skipped_tests do |example|
|
|
49
|
+
case example.metadata[:full_description]
|
|
50
|
+
when /#click_link can download a file$/
|
|
51
|
+
skip 'Need to figure out testing of file downloading on windows platform' if Gem.win_platform?
|
|
52
|
+
end
|
|
53
|
+
end
|
|
49
54
|
|
|
50
55
|
RSpec.describe 'Capybara::Session with chrome' do
|
|
51
56
|
include Capybara::SpecHelper
|
|
@@ -61,14 +61,14 @@ skipped_tests << :windows if ENV['TRAVIS'] && (ENV['SKIP_WINDOW'] || ENV['HEADLE
|
|
|
61
61
|
Capybara::SpecHelper.run_specs TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVER.to_s, capybara_skip: skipped_tests do |example|
|
|
62
62
|
case example.metadata[:full_description]
|
|
63
63
|
when 'Capybara::Session selenium_firefox_remote node #click should allow multiple modifiers'
|
|
64
|
-
|
|
65
|
-
when /^Capybara::Session selenium node #double_click/
|
|
66
|
-
pending "selenium-webdriver/geckodriver doesn't generate double click event" if marionette_lt?(59, @session)
|
|
64
|
+
skip "Firefox doesn't generate an event for shift+control+click" if marionette_gte?(62, @session)
|
|
67
65
|
when 'Capybara::Session selenium_firefox_remote #accept_prompt should accept the prompt with a blank response when there is a default'
|
|
68
66
|
pending "Geckodriver doesn't set a blank response in FF < 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1486485" if marionette_lt?(63, @session)
|
|
69
|
-
when 'Capybara::Session selenium_firefox_remote #attach_file with multipart form should fire change once for each set of files uploaded'
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
when 'Capybara::Session selenium_firefox_remote #attach_file with multipart form should fire change once for each set of files uploaded'
|
|
68
|
+
pending 'Gekcodriver appends files so we have to first call clear for multiple files which creates an extra change ' \
|
|
69
|
+
'if files are already set'
|
|
70
|
+
when 'Capybara::Session selenium_firefox_remote #attach_file with multipart form should fire change once when uploading multiple files from empty'
|
|
71
|
+
pending "FF < 62 doesn't support setting all files at once" if marionette_lt?(62, @session)
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
@@ -51,7 +51,7 @@ $stdout.puts `#{Selenium::WebDriver::Firefox.driver_path} --version` if ENV['CI'
|
|
|
51
51
|
Capybara::SpecHelper.run_specs TestSessions::SeleniumMarionette, 'selenium', capybara_skip: skipped_tests do |example|
|
|
52
52
|
case example.metadata[:full_description]
|
|
53
53
|
when 'Capybara::Session selenium node #click should allow multiple modifiers'
|
|
54
|
-
pending "Firefox doesn't generate an event for shift+control+click" if marionette_gte?(62, @session)
|
|
54
|
+
pending "Firefox doesn't generate an event for shift+control+click" if marionette_gte?(62, @session) && !Gem.win_platform?
|
|
55
55
|
when /^Capybara::Session selenium node #double_click/
|
|
56
56
|
pending "selenium-webdriver/geckodriver doesn't generate double click event" if marionette_lt?(59, @session)
|
|
57
57
|
when 'Capybara::Session selenium #accept_prompt should accept the prompt with a blank response when there is a default'
|
|
@@ -61,6 +61,10 @@ Capybara::SpecHelper.run_specs TestSessions::SeleniumMarionette, 'selenium', cap
|
|
|
61
61
|
'if files are already set'
|
|
62
62
|
when 'Capybara::Session selenium #attach_file with multipart form should fire change once when uploading multiple files from empty'
|
|
63
63
|
pending "FF < 62 doesn't support setting all files at once" if marionette_lt?(62, @session)
|
|
64
|
+
when 'Capybara::Session selenium #accept_confirm should work with nested modals'
|
|
65
|
+
skip 'Broken in FF 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if marionette_gte?(63, @session)
|
|
66
|
+
when 'Capybara::Session selenium #click_link can download a file'
|
|
67
|
+
skip 'Need to figure out testing of file downloading on windows platform' if Gem.win_platform?
|
|
64
68
|
end
|
|
65
69
|
end
|
|
66
70
|
|
|
@@ -202,7 +202,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
|
202
202
|
expect(element.path).to eq('/HTML/BODY/DIV[2]/A[1]')
|
|
203
203
|
end
|
|
204
204
|
|
|
205
|
-
it 'handles namespaces' do
|
|
205
|
+
it 'handles namespaces in xhtml' do
|
|
206
206
|
pending "IE 11 doesn't handle all XPath querys (namespace-uri, etc)" if ie?(session)
|
|
207
207
|
session.visit '/with_namespace'
|
|
208
208
|
rect = session.find(:css, 'div svg rect:first-of-type')
|
|
@@ -210,6 +210,14 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
|
210
210
|
expect(session.find(:xpath, rect.path)).to eq rect
|
|
211
211
|
end
|
|
212
212
|
|
|
213
|
+
it 'handles default namespaces in html5' do
|
|
214
|
+
pending "IE 11 doesn't handle all XPath querys (namespace-uri, etc)" if ie?(session)
|
|
215
|
+
session.visit '/with_html5_svg'
|
|
216
|
+
rect = session.find(:css, 'div svg rect:first-of-type')
|
|
217
|
+
expect(rect.path).to eq("/HTML/BODY/DIV/./*[((local-name(.) = 'svg') and (namespace-uri(.) = 'http://www.w3.org/2000/svg'))]/./*[((local-name(.) = 'rect') and (namespace-uri(.) = 'http://www.w3.org/2000/svg'))][1]")
|
|
218
|
+
expect(session.find(:xpath, rect.path)).to eq rect
|
|
219
|
+
end
|
|
220
|
+
|
|
213
221
|
it 'handles case sensitive element names' do
|
|
214
222
|
pending "IE 11 doesn't handle all XPath querys (namespace-uri, etc)" if ie?(session)
|
|
215
223
|
session.visit '/with_namespace'
|
|
@@ -286,8 +294,12 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
|
286
294
|
end
|
|
287
295
|
|
|
288
296
|
describe 'Element#drag_to' do
|
|
297
|
+
before do
|
|
298
|
+
skip "Firefox < 62 doesn't support a DataTransfer constuctor" if marionette_lt?(62.0, session)
|
|
299
|
+
skip "IE doesn't support a DataTransfer constuctor" if ie?(session)
|
|
300
|
+
end
|
|
301
|
+
|
|
289
302
|
it 'should HTML5 drag and drop an object' do
|
|
290
|
-
pending "Firefox < 62 doesn't support a DataTransfer constuctor" if marionette_lt?(62.0, session)
|
|
291
303
|
session.visit('/with_js')
|
|
292
304
|
element = session.find('//div[@id="drag_html5"]')
|
|
293
305
|
target = session.find('//div[@id="drop_html5"]')
|
|
@@ -306,13 +318,20 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
|
306
318
|
end
|
|
307
319
|
|
|
308
320
|
it 'should HTML5 drag and drop when scrolling needed' do
|
|
309
|
-
pending "Firefox < 62 doesn't support a DataTransfer constuctor" if marionette_lt?(62.0, session)
|
|
310
321
|
session.visit('/with_js')
|
|
311
322
|
element = session.find('//div[@id="drag_html5_scroll"]')
|
|
312
323
|
target = session.find('//div[@id="drop_html5_scroll"]')
|
|
313
324
|
element.drag_to(target)
|
|
314
325
|
expect(session).to have_xpath('//div[contains(., "HTML5 Dropped drag_html5_scroll")]')
|
|
315
326
|
end
|
|
327
|
+
|
|
328
|
+
it 'should drag HTML5 default draggable elements' do
|
|
329
|
+
session.visit('/with_js')
|
|
330
|
+
link = session.find_link('drag_link_html5')
|
|
331
|
+
target = session.find(:id, 'drop_html5')
|
|
332
|
+
link.drag_to target
|
|
333
|
+
expect(session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
|
|
334
|
+
end
|
|
316
335
|
end
|
|
317
336
|
|
|
318
337
|
context 'Windows' do
|
|
@@ -403,6 +422,16 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|
|
403
422
|
end
|
|
404
423
|
end
|
|
405
424
|
end
|
|
425
|
+
|
|
426
|
+
describe ':element selector' do
|
|
427
|
+
it 'can find html5 svg elements' do
|
|
428
|
+
session.visit('with_html5_svg')
|
|
429
|
+
expect(session).to have_selector(:element, :svg)
|
|
430
|
+
expect(session).to have_selector(:element, :rect, visible: true)
|
|
431
|
+
expect(session).to have_selector(:element, :circle)
|
|
432
|
+
expect(session).to have_selector(:element, :linearGradient, visible: :all)
|
|
433
|
+
end
|
|
434
|
+
end
|
|
406
435
|
end
|
|
407
436
|
|
|
408
437
|
def headless_or_remote?
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: capybara
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Thomas Walpole
|
|
@@ -10,7 +10,7 @@ autorequire:
|
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain:
|
|
12
12
|
- gem-public_cert.pem
|
|
13
|
-
date: 2018-09-
|
|
13
|
+
date: 2018-09-20 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: addressable
|
|
@@ -311,9 +311,11 @@ files:
|
|
|
311
311
|
- lib/capybara/selenium/driver.rb
|
|
312
312
|
- lib/capybara/selenium/driver_specializations/chrome_driver.rb
|
|
313
313
|
- lib/capybara/selenium/driver_specializations/marionette_driver.rb
|
|
314
|
+
- lib/capybara/selenium/extensions/html5_drag.rb
|
|
314
315
|
- lib/capybara/selenium/node.rb
|
|
315
316
|
- lib/capybara/selenium/nodes/chrome_node.rb
|
|
316
317
|
- lib/capybara/selenium/nodes/marionette_node.rb
|
|
318
|
+
- lib/capybara/selenium/patches/pause_duration_fix.rb
|
|
317
319
|
- lib/capybara/server.rb
|
|
318
320
|
- lib/capybara/server/animation_disabler.rb
|
|
319
321
|
- lib/capybara/server/checker.rb
|
|
@@ -437,6 +439,7 @@ files:
|
|
|
437
439
|
- lib/capybara/spec/views/with_fixed_header_footer.erb
|
|
438
440
|
- lib/capybara/spec/views/with_hover.erb
|
|
439
441
|
- lib/capybara/spec/views/with_html.erb
|
|
442
|
+
- lib/capybara/spec/views/with_html5_svg.erb
|
|
440
443
|
- lib/capybara/spec/views/with_html_entities.erb
|
|
441
444
|
- lib/capybara/spec/views/with_js.erb
|
|
442
445
|
- lib/capybara/spec/views/with_namespace.erb
|