capybara 3.2.1 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +22 -1
- data/README.md +1 -1
- data/lib/capybara.rb +2 -0
- data/lib/capybara/driver/base.rb +5 -1
- data/lib/capybara/driver/node.rb +4 -0
- data/lib/capybara/helpers.rb +25 -0
- data/lib/capybara/minitest.rb +7 -1
- data/lib/capybara/minitest/spec.rb +8 -1
- data/lib/capybara/node/base.rb +3 -3
- data/lib/capybara/node/element.rb +52 -0
- data/lib/capybara/node/matchers.rb +33 -0
- data/lib/capybara/queries/selector_query.rb +4 -4
- data/lib/capybara/queries/style_query.rb +41 -0
- data/lib/capybara/rack_test/browser.rb +7 -1
- data/lib/capybara/rack_test/node.rb +4 -0
- data/lib/capybara/rspec/compound.rb +67 -65
- data/lib/capybara/rspec/features.rb +2 -4
- data/lib/capybara/rspec/matchers.rb +30 -10
- data/lib/capybara/selector.rb +9 -0
- data/lib/capybara/selector/css.rb +74 -1
- data/lib/capybara/selector/filters/base.rb +2 -1
- data/lib/capybara/selector/filters/expression_filter.rb +2 -1
- data/lib/capybara/selector/selector.rb +1 -1
- data/lib/capybara/selenium/driver.rb +34 -43
- data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +35 -0
- data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +31 -0
- data/lib/capybara/selenium/node.rb +17 -20
- data/lib/capybara/selenium/nodes/marionette_node.rb +31 -0
- data/lib/capybara/server.rb +8 -29
- data/lib/capybara/server/checker.rb +38 -0
- data/lib/capybara/spec/public/test.js +5 -0
- data/lib/capybara/spec/session/all_spec.rb +4 -0
- data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
- data/lib/capybara/spec/session/click_button_spec.rb +10 -0
- data/lib/capybara/spec/session/click_link_spec.rb +11 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +2 -0
- data/lib/capybara/spec/session/find_link_spec.rb +18 -0
- data/lib/capybara/spec/session/find_spec.rb +1 -0
- data/lib/capybara/spec/session/first_spec.rb +1 -0
- data/lib/capybara/spec/session/has_css_spec.rb +0 -6
- data/lib/capybara/spec/session/has_style_spec.rb +25 -0
- data/lib/capybara/spec/session/node_spec.rb +34 -0
- data/lib/capybara/spec/session/save_page_spec.rb +4 -1
- data/lib/capybara/spec/session/save_screenshot_spec.rb +3 -1
- data/lib/capybara/spec/session/text_spec.rb +1 -0
- data/lib/capybara/spec/session/title_spec.rb +1 -0
- data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -0
- data/lib/capybara/spec/session/window/window_spec.rb +20 -0
- data/lib/capybara/spec/session/window/windows_spec.rb +1 -0
- data/lib/capybara/spec/session/window/within_window_spec.rb +1 -0
- data/lib/capybara/spec/session/within_spec.rb +1 -0
- data/lib/capybara/spec/spec_helper.rb +3 -1
- data/lib/capybara/spec/test_app.rb +18 -0
- data/lib/capybara/spec/views/form.erb +8 -0
- data/lib/capybara/spec/views/tables.erb +1 -1
- data/lib/capybara/spec/views/with_html.erb +9 -2
- data/lib/capybara/spec/views/with_js.erb +4 -0
- data/lib/capybara/spec/views/with_namespace.erb +20 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +11 -0
- data/spec/css_splitter_spec.rb +38 -0
- data/spec/dsl_spec.rb +1 -1
- data/spec/minitest_spec.rb +7 -1
- data/spec/minitest_spec_spec.rb +8 -1
- data/spec/rack_test_spec.rb +10 -0
- data/spec/rspec/shared_spec_matchers.rb +2 -0
- data/spec/selenium_spec_chrome.rb +28 -0
- data/spec/selenium_spec_chrome_remote.rb +2 -2
- data/spec/selenium_spec_marionette.rb +21 -1
- data/spec/server_spec.rb +0 -1
- data/spec/shared_selenium_session.rb +16 -1
- metadata +18 -19
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/selenium/nodes/marionette_node'
|
4
|
+
|
5
|
+
module Capybara::Selenium::Driver::MarionetteDriver
|
6
|
+
def resize_window_to(handle, width, height)
|
7
|
+
within_given_window(handle) do
|
8
|
+
# Don't set the size if already set - See https://github.com/mozilla/geckodriver/issues/643
|
9
|
+
if window_size(handle) == [width, height]
|
10
|
+
{}
|
11
|
+
else
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def reset!
|
18
|
+
# Use instance variable directly so we avoid starting the browser just to reset the session
|
19
|
+
return unless @browser
|
20
|
+
|
21
|
+
switch_to_window(window_handles.first)
|
22
|
+
window_handles.slice(1..-1).each { |win| close_window(win) }
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def build_node(native_node)
|
29
|
+
::Capybara::Selenium::MarionetteNode.new(self, native_node)
|
30
|
+
end
|
31
|
+
end
|
@@ -28,6 +28,12 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
def style(styles)
|
32
|
+
styles.each_with_object({}) do |style, result|
|
33
|
+
result[style] = native.css_value(style)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
31
37
|
##
|
32
38
|
#
|
33
39
|
# Set the value of the form element to the given value.
|
@@ -91,6 +97,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
91
97
|
e.message =~ /Other element would receive the click/
|
92
98
|
scroll_to_center
|
93
99
|
end
|
100
|
+
|
94
101
|
raise e
|
95
102
|
end
|
96
103
|
|
@@ -133,18 +140,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
133
140
|
alias :checked? :selected?
|
134
141
|
|
135
142
|
def disabled?
|
136
|
-
|
137
|
-
|
138
|
-
# workaround for selenium-webdriver/geckodriver reporting elements as enabled when they are nested in disabling elements
|
139
|
-
if driver.marionette?
|
140
|
-
if %w[option optgroup].include? tag_name
|
141
|
-
find_xpath("parent::*[self::optgroup or self::select]")[0].disabled?
|
142
|
-
else
|
143
|
-
!find_xpath("parent::fieldset[@disabled] | ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]").empty?
|
144
|
-
end
|
145
|
-
else
|
146
|
-
false
|
147
|
-
end
|
143
|
+
!native.enabled?
|
148
144
|
end
|
149
145
|
|
150
146
|
def content_editable?
|
@@ -167,9 +163,15 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
167
163
|
path = find_xpath(XPath.ancestor_or_self).reverse
|
168
164
|
|
169
165
|
result = []
|
166
|
+
default_ns = path.last[:namespaceURI]
|
170
167
|
while (node = path.shift)
|
171
168
|
parent = path.first
|
172
|
-
selector = node
|
169
|
+
selector = node[:tagName]
|
170
|
+
if node[:namespaceURI] != default_ns
|
171
|
+
selector = XPath.child.where((XPath.local_name == selector) & (XPath.namespace_uri == node[:namespaceURI])).to_s
|
172
|
+
selector
|
173
|
+
end
|
174
|
+
|
173
175
|
if parent
|
174
176
|
siblings = parent.find_xpath(selector)
|
175
177
|
selector += "[#{siblings.index(node) + 1}]" unless siblings.size == 1
|
@@ -265,17 +267,12 @@ private
|
|
265
267
|
arguments[0].dispatchEvent(new InputEvent('input'));
|
266
268
|
arguments[0].dispatchEvent(new Event('change', { bubbles: true }));
|
267
269
|
}
|
268
|
-
|
270
|
+
JS
|
269
271
|
end
|
270
272
|
|
271
273
|
def set_file(value) # rubocop:disable Naming/AccessorMethodName
|
272
274
|
path_names = value.to_s.empty? ? [] : value
|
273
|
-
|
274
|
-
native.clear
|
275
|
-
Array(path_names).each { |p| native.send_keys(p) }
|
276
|
-
else
|
277
|
-
native.send_keys(Array(path_names).join("\n"))
|
278
|
-
end
|
275
|
+
native.send_keys(Array(path_names).join("\n"))
|
279
276
|
end
|
280
277
|
|
281
278
|
def set_content_editable(value) # rubocop:disable Naming/AccessorMethodName
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Capybara::Selenium::MarionetteNode < Capybara::Selenium::Node
|
4
|
+
def click(keys = [], **options)
|
5
|
+
super
|
6
|
+
rescue ::Selenium::WebDriver::Error::ElementNotInteractableError
|
7
|
+
if tag_name == "tr"
|
8
|
+
warn "You are attempting to click a table row which has issues in geckodriver/marionette - see https://github.com/mozilla/geckodriver/issues/1228. " \
|
9
|
+
"Your test should probably be clicking on a table cell like a user would. Clicking the first cell in the row instead."
|
10
|
+
return find_css('th:first-child,td:first-child')[0].click
|
11
|
+
end
|
12
|
+
raise
|
13
|
+
end
|
14
|
+
|
15
|
+
def disabled?
|
16
|
+
return true if super
|
17
|
+
|
18
|
+
# workaround for selenium-webdriver/geckodriver reporting elements as enabled when they are nested in disabling elements
|
19
|
+
if %w[option optgroup].include? tag_name
|
20
|
+
find_xpath("parent::*[self::optgroup or self::select]")[0].disabled?
|
21
|
+
else
|
22
|
+
!find_xpath("parent::fieldset[@disabled] | ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]").empty?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_file(value) # rubocop:disable Naming/AccessorMethodName
|
27
|
+
path_names = value.to_s.empty? ? [] : value
|
28
|
+
native.clear
|
29
|
+
Array(path_names).each { |p| native.send_keys(p) }
|
30
|
+
end
|
31
|
+
end
|
data/lib/capybara/server.rb
CHANGED
@@ -5,6 +5,7 @@ require 'net/http'
|
|
5
5
|
require 'rack'
|
6
6
|
require 'capybara/server/middleware'
|
7
7
|
require 'capybara/server/animation_disabler'
|
8
|
+
require 'capybara/server/checker'
|
8
9
|
|
9
10
|
module Capybara
|
10
11
|
class Server
|
@@ -23,10 +24,10 @@ module Capybara
|
|
23
24
|
@server_thread = nil # suppress warnings
|
24
25
|
@host = deprecated_options[1] || host
|
25
26
|
@reportable_errors = deprecated_options[2] || reportable_errors
|
26
|
-
@using_ssl = false
|
27
27
|
@port = deprecated_options[0] || port
|
28
28
|
@port ||= Capybara::Server.ports[port_key]
|
29
29
|
@port ||= find_available_port(host)
|
30
|
+
@checker = Checker.new(@host, @port)
|
30
31
|
end
|
31
32
|
|
32
33
|
def reset_error!
|
@@ -38,22 +39,12 @@ module Capybara
|
|
38
39
|
end
|
39
40
|
|
40
41
|
def using_ssl?
|
41
|
-
@
|
42
|
+
@checker.ssl?
|
42
43
|
end
|
43
44
|
|
44
45
|
def responsive?
|
45
46
|
return false if @server_thread&.join(0)
|
46
|
-
|
47
|
-
begin
|
48
|
-
res = if !using_ssl?
|
49
|
-
http_connect
|
50
|
-
else
|
51
|
-
https_connect
|
52
|
-
end
|
53
|
-
rescue EOFError, Net::ReadTimeout
|
54
|
-
res = https_connect
|
55
|
-
@using_ssl = true
|
56
|
-
end
|
47
|
+
res = @checker.request { |http| http.get('/__identify__') }
|
57
48
|
|
58
49
|
if res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPRedirection)
|
59
50
|
return res.body == app.object_id.to_s
|
@@ -63,11 +54,9 @@ module Capybara
|
|
63
54
|
end
|
64
55
|
|
65
56
|
def wait_for_pending_requests
|
66
|
-
|
57
|
+
timer = Capybara::Helpers.timer(expire_in: 60)
|
67
58
|
while pending_requests?
|
68
|
-
|
69
|
-
raise "Requests did not finish in 60 seconds"
|
70
|
-
end
|
59
|
+
raise "Requests did not finish in 60 seconds" if timer.expired?
|
71
60
|
sleep 0.01
|
72
61
|
end
|
73
62
|
end
|
@@ -80,11 +69,9 @@ module Capybara
|
|
80
69
|
Capybara.server.call(middleware, port, host)
|
81
70
|
end
|
82
71
|
|
83
|
-
|
72
|
+
timer = Capybara::Helpers.timer(expire_in: 60)
|
84
73
|
until responsive?
|
85
|
-
|
86
|
-
raise "Rack application timed out during boot"
|
87
|
-
end
|
74
|
+
raise "Rack application timed out during boot" if timer.expired?
|
88
75
|
@server_thread.join(0.1)
|
89
76
|
end
|
90
77
|
end
|
@@ -94,14 +81,6 @@ module Capybara
|
|
94
81
|
|
95
82
|
private
|
96
83
|
|
97
|
-
def http_connect
|
98
|
-
Net::HTTP.start(host, port, read_timeout: 2) { |http| http.get('/__identify__') }
|
99
|
-
end
|
100
|
-
|
101
|
-
def https_connect
|
102
|
-
Net::HTTP.start(host, port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) { |http| http.get('/__identify__') }
|
103
|
-
end
|
104
|
-
|
105
84
|
def middleware
|
106
85
|
@middleware ||= Middleware.new(app, @reportable_errors, @extra_middleware)
|
107
86
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
class Server
|
5
|
+
class Checker
|
6
|
+
def initialize(host, port)
|
7
|
+
@host, @port = host, port
|
8
|
+
@ssl = false
|
9
|
+
end
|
10
|
+
|
11
|
+
def request(&block)
|
12
|
+
ssl? ? https_request(&block) : http_request(&block)
|
13
|
+
rescue EOFError, Net::ReadTimeout
|
14
|
+
res = https_request(&block)
|
15
|
+
@ssl = true
|
16
|
+
res
|
17
|
+
end
|
18
|
+
|
19
|
+
def ssl?
|
20
|
+
@ssl
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def http_request(&block)
|
26
|
+
Net::HTTP.start(@host, @port, read_timeout: 2, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def https_request(&block)
|
30
|
+
Net::HTTP.start(@host, @port, ssl_options, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def ssl_options
|
34
|
+
{ use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -63,6 +63,11 @@ $(function() {
|
|
63
63
|
$('title').text('changed title')
|
64
64
|
}, 400)
|
65
65
|
});
|
66
|
+
$('#change-size').click(function() {
|
67
|
+
setTimeout(function() {
|
68
|
+
document.getElementById('change').style.fontSize = '50px';
|
69
|
+
}, 500)
|
70
|
+
});
|
66
71
|
$('#click-test').on({
|
67
72
|
click: function(e) {
|
68
73
|
var desc = "";
|
@@ -59,6 +59,7 @@ Capybara::SpecHelper.spec "#all" do
|
|
59
59
|
|
60
60
|
context "with css as default selector" do
|
61
61
|
before { Capybara.default_selector = :css }
|
62
|
+
|
62
63
|
it "should find the first element using the given locator" do
|
63
64
|
expect(@session.all('h1').first.text).to eq('This is a test')
|
64
65
|
expect(@session.all("input[id='test_field']").first.value).to eq('monkey')
|
@@ -102,6 +103,7 @@ Capybara::SpecHelper.spec "#all" do
|
|
102
103
|
expect { @session.all(:css, 'h1, p', count: 5) }.to raise_error(Capybara::ExpectationNotMet)
|
103
104
|
end
|
104
105
|
end
|
106
|
+
|
105
107
|
context ':minimum' do
|
106
108
|
it 'should succeed when the number of elements founds matches the expectation' do
|
107
109
|
expect { @session.all(:css, 'h1, p', minimum: 0) }.not_to raise_error
|
@@ -110,6 +112,7 @@ Capybara::SpecHelper.spec "#all" do
|
|
110
112
|
expect { @session.all(:css, 'h1, p', minimum: 5) }.to raise_error(Capybara::ExpectationNotMet)
|
111
113
|
end
|
112
114
|
end
|
115
|
+
|
113
116
|
context ':maximum' do
|
114
117
|
it 'should succeed when the number of elements founds matches the expectation' do
|
115
118
|
expect { @session.all(:css, 'h1, p', maximum: 4) }.not_to raise_error
|
@@ -118,6 +121,7 @@ Capybara::SpecHelper.spec "#all" do
|
|
118
121
|
expect { @session.all(:css, 'h1, p', maximum: 0) }.to raise_error(Capybara::ExpectationNotMet)
|
119
122
|
end
|
120
123
|
end
|
124
|
+
|
121
125
|
context ':between' do
|
122
126
|
it 'should succeed when the number of elements founds matches the expectation' do
|
123
127
|
expect { @session.all(:css, 'h1, p', between: 2..7) }.not_to raise_error
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Capybara::SpecHelper.spec '#assert_style', requires: [:css] do
|
4
|
+
it "should not raise if the elements style contains the given properties" do
|
5
|
+
@session.visit('/with_html')
|
6
|
+
expect do
|
7
|
+
@session.find(:css, '#first').assert_style(display: 'block')
|
8
|
+
end.not_to raise_error
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should raise error if the elements style doesn't contain the given properties" do
|
12
|
+
@session.visit('/with_html')
|
13
|
+
expect do
|
14
|
+
@session.find(:css, '#first').assert_style(display: 'inline')
|
15
|
+
end.to raise_error(Capybara::ExpectationNotMet, 'Expected node to have styles {"display"=>"inline"}. Actual styles were {"display"=>"block"}')
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should wait for style", requires: %i[css js] do
|
19
|
+
@session.visit('/with_js')
|
20
|
+
el = @session.find(:css, '#change')
|
21
|
+
@session.click_link("Change size")
|
22
|
+
expect do
|
23
|
+
el.assert_style({ 'font-size': '50px' }, wait: 3)
|
24
|
+
end.not_to raise_error
|
25
|
+
end
|
26
|
+
end
|
@@ -396,6 +396,16 @@ Capybara::SpecHelper.spec '#click_button' do
|
|
396
396
|
expect(@session.current_url).to match(%r{/landed$})
|
397
397
|
end
|
398
398
|
|
399
|
+
it "should follow temporary redirects that maintain method" do
|
400
|
+
@session.click_button('Go 307')
|
401
|
+
expect(@session).to have_content('You post landed: TWTW')
|
402
|
+
end
|
403
|
+
|
404
|
+
it "should follow permanent redirects that maintain method" do
|
405
|
+
@session.click_button('Go 308')
|
406
|
+
expect(@session).to have_content('You post landed: TWTW')
|
407
|
+
end
|
408
|
+
|
399
409
|
it "should post pack to the same URL when no action given" do
|
400
410
|
@session.visit('/postback')
|
401
411
|
@session.click_button('With no action')
|
@@ -203,4 +203,15 @@ Capybara::SpecHelper.spec '#click_link' do
|
|
203
203
|
el = @session.find(:link, 'Normal Anchor')
|
204
204
|
expect(@session.click_link('Normal Anchor')).to eq el
|
205
205
|
end
|
206
|
+
|
207
|
+
it "can download a file", requires: [:download] do
|
208
|
+
# This requires the driver used for the test to be configured
|
209
|
+
# to download documents with the mime type "text/csv"
|
210
|
+
download_file = File.join(Capybara.save_path, 'download.csv')
|
211
|
+
expect(File).not_to exist(download_file)
|
212
|
+
@session.click_link('Download Me')
|
213
|
+
sleep 2
|
214
|
+
expect(File).to exist(download_file)
|
215
|
+
FileUtils.rm_rf download_file
|
216
|
+
end
|
206
217
|
end
|
@@ -188,7 +188,9 @@ Capybara::SpecHelper.spec "#fill_in" do
|
|
188
188
|
|
189
189
|
context "with ignore_hidden_fields" do
|
190
190
|
before { Capybara.ignore_hidden_elements = true }
|
191
|
+
|
191
192
|
after { Capybara.ignore_hidden_elements = false }
|
193
|
+
|
192
194
|
it "should not find a hidden field" do
|
193
195
|
msg = "Unable to find visible field \"Super Secret\" that is not disabled"
|
194
196
|
expect do
|
@@ -49,4 +49,22 @@ Capybara::SpecHelper.spec '#find_link' do
|
|
49
49
|
expect(@session.find_link(href: '#anchor').text).to eq "Normal Anchor"
|
50
50
|
end
|
51
51
|
end
|
52
|
+
|
53
|
+
context "download filter" do
|
54
|
+
it "finds a download link" do
|
55
|
+
expect(@session.find_link("Download Me", download: true).text).to eq "Download Me"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "doesn't find a download link if download is false" do
|
59
|
+
expect { @session.find_link("Download Me", download: false) }.to raise_error Capybara::ElementNotFound
|
60
|
+
end
|
61
|
+
|
62
|
+
it "finds a renaming download link" do
|
63
|
+
expect(@session.find_link(download: "other.csv").text).to eq "Download Other"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "raises if passed an invalid value" do
|
67
|
+
expect { @session.find_link(download: 37) }.to raise_error ArgumentError
|
68
|
+
end
|
69
|
+
end
|
52
70
|
end
|
@@ -206,6 +206,7 @@ Capybara::SpecHelper.spec '#find' do
|
|
206
206
|
|
207
207
|
context "with css as default selector" do
|
208
208
|
before { Capybara.default_selector = :css }
|
209
|
+
|
209
210
|
it "should find the first element using the given locator" do
|
210
211
|
expect(@session.find('h1').text).to eq('This is a test')
|
211
212
|
expect(@session.find("input[id='test_field']").value).to eq('monkey')
|
@@ -51,6 +51,7 @@ Capybara::SpecHelper.spec '#first' do
|
|
51
51
|
|
52
52
|
context "with css as default selector" do
|
53
53
|
before { Capybara.default_selector = :css }
|
54
|
+
|
54
55
|
it "should find the first element using the given locator" do
|
55
56
|
expect(@session.first('h1').text).to eq('This is a test')
|
56
57
|
expect(@session.first("input[id='test_field']").value).to eq('monkey')
|
@@ -115,12 +115,6 @@ Capybara::SpecHelper.spec '#has_css?' do
|
|
115
115
|
end
|
116
116
|
|
117
117
|
it "should allow escapes in the CSS selector" do
|
118
|
-
if (defined?(TestClass) && @session.is_a?(TestClass)) || @session.driver.is_a?(Capybara::RackTest::Driver)
|
119
|
-
# Nokogiri doesn't unescape CSS selectors when converting from CSS to XPath
|
120
|
-
# See: https://github.com/teamcapybara/capybara/issues/1866
|
121
|
-
# Also: https://github.com/sparklemotion/nokogiri/pull/1646
|
122
|
-
pending "Current Nokogiri doesn't handle escapes in CSS attribute selectors correctly"
|
123
|
-
end
|
124
118
|
expect(@session).to have_css('p[data-random="abc\\\\def"]')
|
125
119
|
expect(@session).to have_css("p[data-random='#{Capybara::Selector::CSS.escape('abc\def')}']")
|
126
120
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Capybara::SpecHelper.spec '#has_style?', requires: [:css] do
|
4
|
+
before do
|
5
|
+
@session.visit('/with_html')
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should be true if the element has the given style" do
|
9
|
+
expect(@session.find(:css, '#first')).to have_style(display: 'block')
|
10
|
+
expect(@session.find(:css, '#first').has_style?(display: 'block')).to be true
|
11
|
+
expect(@session.find(:css, '#second')).to have_style('display' => 'inline')
|
12
|
+
expect(@session.find(:css, '#second').has_style?('display' => 'inline')).to be true
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be false if the element does not have the given style" do
|
16
|
+
expect(@session.find(:css, '#first').has_style?('display' => 'inline')).to be false
|
17
|
+
expect(@session.find(:css, '#second').has_style?(display: 'block')).to be false
|
18
|
+
end
|
19
|
+
|
20
|
+
it "allows Regexp for value matching" do
|
21
|
+
expect(@session.find(:css, '#first')).to have_style(display: /^bl/)
|
22
|
+
expect(@session.find(:css, '#first').has_style?('display' => /^bl/)).to be true
|
23
|
+
expect(@session.find(:css, '#first').has_style?(display: /^in/)).to be false
|
24
|
+
end
|
25
|
+
end
|