capybara 3.0.3 → 3.1.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 +10 -0
- data/lib/capybara.rb +1 -1
- data/lib/capybara/helpers.rb +1 -1
- data/lib/capybara/minitest/spec.rb +2 -0
- data/lib/capybara/node/actions.rb +45 -5
- data/lib/capybara/queries/match_query.rb +2 -0
- data/lib/capybara/queries/selector_query.rb +3 -4
- data/lib/capybara/queries/text_query.rb +4 -5
- data/lib/capybara/rack_test/node.rb +6 -4
- data/lib/capybara/result.rb +1 -1
- data/lib/capybara/rspec/compound.rb +2 -0
- data/lib/capybara/selector.rb +72 -18
- data/lib/capybara/selector/css.rb +2 -0
- data/lib/capybara/selenium/driver.rb +14 -15
- data/lib/capybara/selenium/node.rb +23 -29
- data/lib/capybara/server.rb +29 -4
- data/lib/capybara/session.rb +12 -13
- data/lib/capybara/spec/session/all_spec.rb +6 -6
- data/lib/capybara/spec/session/{assert_current_path.rb → assert_current_path_spec.rb} +2 -3
- data/lib/capybara/spec/session/{assert_selector.rb → assert_selector_spec.rb} +0 -0
- data/lib/capybara/spec/session/{assert_text.rb → assert_text_spec.rb} +1 -1
- data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +0 -0
- data/lib/capybara/spec/session/check_spec.rb +6 -6
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +0 -7
- data/lib/capybara/spec/session/current_url_spec.rb +6 -8
- data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +2 -0
- data/lib/capybara/spec/session/element/match_css_spec.rb +2 -0
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +2 -0
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +2 -0
- data/lib/capybara/spec/session/find_by_id_spec.rb +1 -1
- data/lib/capybara/spec/session/find_field_spec.rb +1 -1
- data/lib/capybara/spec/session/first_spec.rb +12 -12
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +1 -1
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +1 -1
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +2 -2
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +1 -1
- data/lib/capybara/spec/session/has_button_spec.rb +5 -0
- data/lib/capybara/spec/session/has_current_path_spec.rb +2 -2
- data/lib/capybara/spec/session/has_field_spec.rb +1 -1
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +2 -0
- data/lib/capybara/spec/session/has_selector_spec.rb +8 -0
- data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +0 -0
- data/lib/capybara/spec/session/node_spec.rb +4 -4
- data/lib/capybara/spec/session/reset_session_spec.rb +2 -2
- data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +0 -0
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -1
- data/lib/capybara/spec/session/select_spec.rb +27 -1
- data/lib/capybara/spec/session/selectors_spec.rb +2 -0
- data/lib/capybara/spec/session/uncheck_spec.rb +3 -3
- data/lib/capybara/spec/session/visit_spec.rb +17 -10
- data/lib/capybara/spec/session/window/become_closed_spec.rb +3 -3
- data/lib/capybara/spec/session/window/current_window_spec.rb +2 -2
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +3 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +5 -5
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +3 -3
- data/lib/capybara/spec/session/window/window_spec.rb +24 -9
- data/lib/capybara/spec/session/window/windows_spec.rb +2 -2
- data/lib/capybara/spec/session/window/within_window_spec.rb +2 -2
- data/lib/capybara/spec/session/within_spec.rb +3 -3
- data/lib/capybara/spec/spec_helper.rb +7 -5
- data/lib/capybara/spec/views/form.erb +9 -0
- data/lib/capybara/version.rb +1 -1
- data/spec/basic_node_spec.rb +1 -1
- data/spec/capybara_spec.rb +4 -14
- data/spec/dsl_spec.rb +5 -3
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -2
- data/spec/fixtures/selenium_driver_rspec_success.rb +2 -2
- data/spec/rack_test_spec.rb +8 -6
- data/spec/result_spec.rb +22 -2
- data/spec/rspec/features_spec.rb +4 -2
- data/spec/rspec/scenarios_spec.rb +1 -1
- data/spec/rspec/shared_spec_matchers.rb +7 -4
- data/spec/rspec/views_spec.rb +2 -1
- data/spec/rspec_spec.rb +80 -78
- data/spec/selenium_spec_marionette.rb +6 -4
- data/spec/server_spec.rb +40 -2
- data/spec/session_spec.rb +12 -4
- data/spec/shared_selenium_session.rb +106 -84
- metadata +11 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75ca733cee9a96dd5d17e4ae8ed453686c73d4deaf77fae6fa4008b13b62e12d
|
4
|
+
data.tar.gz: ed22e70d57b1baac7bf6aafd9f483acf16f07193fb087e872b94d24b44134165
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a221f4ae1099fa5367af6c60396263d35f1d1d0fdcc8d5fda712a4ca8f3b32e3ca6de14fae15dcf39e2a76f24c91555a6ac2c5745d4d9185ecbb80a0a34e463b
|
7
|
+
data.tar.gz: 41034edf9b5cf28ab1850a9f499996a4c3903cb75d77112c7d83fe342e7b097a89a83bdfff36750294bf113ba65d07e3db4500eeff8e618e48fa5e55c4e405c8
|
data/History.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
# Version 3.1.0
|
2
|
+
Release date: 2018-05-10
|
3
|
+
|
4
|
+
### Added
|
5
|
+
|
6
|
+
* Support for using `select` with text inputs associated with a datalist element
|
7
|
+
* `type` filter on `:button` selector
|
8
|
+
* Support for server operating in https mode
|
9
|
+
* Selenium driver now uses JS to fill_in/set date and time fields when passed date or time objects [Aleksei Gusev, Thomas Walpole]
|
10
|
+
|
1
11
|
# Version 3.0.3
|
2
12
|
Release date: 2018-04-30
|
3
13
|
|
data/lib/capybara.rb
CHANGED
@@ -497,6 +497,6 @@ Capybara.register_driver :selenium_chrome_headless do |app|
|
|
497
497
|
Capybara::Selenium::Driver.load_selenium
|
498
498
|
browser_options = ::Selenium::WebDriver::Chrome::Options.new
|
499
499
|
browser_options.args << '--headless'
|
500
|
-
browser_options.args << '--disable-gpu'
|
500
|
+
browser_options.args << '--disable-gpu' if Gem.win_platform?
|
501
501
|
Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
|
502
502
|
end
|
data/lib/capybara/helpers.rb
CHANGED
@@ -158,8 +158,8 @@ module Capybara
|
|
158
158
|
|
159
159
|
##
|
160
160
|
#
|
161
|
-
# If `:from` option is present, `select` finds a select box
|
162
|
-
# and selects a particular option from it.
|
161
|
+
# If `:from` option is present, `select` finds a select box, or text input with associated datalist,
|
162
|
+
# on the page and selects a particular option from it.
|
163
163
|
# Otherwise it finds an option inside current scope and selects it.
|
164
164
|
# If the select box is a multiple select, +select+ can be called multiple times to select more than
|
165
165
|
# one option.
|
@@ -169,13 +169,47 @@ module Capybara
|
|
169
169
|
#
|
170
170
|
# @macro waiting_behavior
|
171
171
|
#
|
172
|
-
# @param [String] value
|
172
|
+
# @param [String] value Which option to select
|
173
173
|
# @option options [String] :from The id, name or label of the select box
|
174
174
|
#
|
175
175
|
# @return [Capybara::Node::Element] The option element selected
|
176
176
|
def select(value = nil, from: nil, **options)
|
177
|
-
scope =
|
178
|
-
|
177
|
+
scope = if from
|
178
|
+
synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
|
179
|
+
begin
|
180
|
+
find(:select, from, options)
|
181
|
+
rescue Capybara::ElementNotFound => select_error
|
182
|
+
raise if %i[selected with_selected multiple].any? { |option| options.key?(option) }
|
183
|
+
begin
|
184
|
+
find(:datalist_input, from, options)
|
185
|
+
rescue Capybara::ElementNotFound => dlinput_error
|
186
|
+
raise Capybara::ElementNotFound, "#{select_error.message} and #{dlinput_error.message}"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
else
|
191
|
+
self
|
192
|
+
end
|
193
|
+
|
194
|
+
if scope.respond_to?(:tag_name) && scope.tag_name == "input"
|
195
|
+
begin
|
196
|
+
# TODO: this is a more efficient but won't work with non-JS drivers
|
197
|
+
# datalist_options = session.evaluate_script('Array.prototype.slice.call((arguments[0].list||{}).options || []).filter(function(el){ return !el.disabled }).map(function(el){ return { "value": el.value, "label": el.label} })', scope)
|
198
|
+
datalist_options = session.evaluate_script(DATALIST_OPTIONS_SCRIPT, scope)
|
199
|
+
if (option = datalist_options.find { |o| o['value'] == value || o['label'] == value })
|
200
|
+
scope.set(option["value"])
|
201
|
+
else
|
202
|
+
raise ::Capybara::ElementNotFound, "Unable to find datalist option \"#{value}\""
|
203
|
+
end
|
204
|
+
rescue ::Capybara::NotSupportedByDriverError
|
205
|
+
# Implement for drivers that don't support JS
|
206
|
+
datalist = find(:xpath, XPath.descendant(:datalist)[XPath.attr(:id) == scope[:list]], visible: false)
|
207
|
+
option = datalist.find(:datalist_option, value, disabled: false)
|
208
|
+
scope.set(option.value)
|
209
|
+
end
|
210
|
+
else
|
211
|
+
scope.find(:option, value, options).select_option
|
212
|
+
end
|
179
213
|
end
|
180
214
|
|
181
215
|
##
|
@@ -291,6 +325,12 @@ module Capybara
|
|
291
325
|
delete el.capybara_style_cache;
|
292
326
|
}
|
293
327
|
JS
|
328
|
+
|
329
|
+
DATALIST_OPTIONS_SCRIPT = <<-'JS'.freeze
|
330
|
+
Array.prototype.slice.call((arguments[0].list||{}).options || []).
|
331
|
+
filter(function(el){ return !el.disabled }).
|
332
|
+
map(function(el){ return { "value": el.value, "label": el.label} })
|
333
|
+
JS
|
294
334
|
end
|
295
335
|
end
|
296
336
|
end
|
@@ -35,7 +35,7 @@ module Capybara
|
|
35
35
|
@description << "visible " if visible == :visible
|
36
36
|
@description << "non-visible " if visible == :hidden
|
37
37
|
@description << "#{label} #{locator.inspect}"
|
38
|
-
@description << " with#{
|
38
|
+
@description << " with#{' exact' if exact_text == true} text #{options[:text].inspect}" if options[:text]
|
39
39
|
@description << " with exact text #{options[:exact_text]}" if options[:exact_text].is_a?(String)
|
40
40
|
@description << " with id #{options[:id]}" if options[:id]
|
41
41
|
@description << " with classes [#{Array(options[:class]).join(',')}]" if options[:class]
|
@@ -167,9 +167,8 @@ module Capybara
|
|
167
167
|
|
168
168
|
def assert_valid_keys
|
169
169
|
super
|
170
|
-
|
171
|
-
|
172
|
-
end
|
170
|
+
return if VALID_MATCH.include?(match)
|
171
|
+
raise ArgumentError, "invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(', ')}"
|
173
172
|
end
|
174
173
|
|
175
174
|
def filtered_xpath(expr)
|
@@ -39,7 +39,7 @@ module Capybara
|
|
39
39
|
if @expected_text.is_a?(Regexp)
|
40
40
|
"text matching #{@expected_text.inspect}"
|
41
41
|
else
|
42
|
-
"#{
|
42
|
+
"#{'exact ' if exact?}text #{@expected_text.inspect}"
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
@@ -68,16 +68,15 @@ module Capybara
|
|
68
68
|
def case_insensitive_message
|
69
69
|
insensitive_regexp = Capybara::Helpers.to_regexp(@expected_text, options: Regexp::IGNORECASE)
|
70
70
|
insensitive_count = @actual_text.scan(insensitive_regexp).size
|
71
|
-
if insensitive_count
|
72
|
-
|
73
|
-
end
|
71
|
+
return if insensitive_count == @count
|
72
|
+
"it was found #{insensitive_count} #{Capybara::Helpers.declension('time', 'times', insensitive_count)} using a case insensitive search"
|
74
73
|
end
|
75
74
|
|
76
75
|
def invisible_message
|
77
76
|
invisible_text = text(@node, :all)
|
78
77
|
invisible_count = invisible_text.scan(@search_regexp).size
|
79
78
|
if invisible_count != @count
|
80
|
-
"it was found #{invisible_count} #{Capybara::Helpers.declension(
|
79
|
+
"it was found #{invisible_count} #{Capybara::Helpers.declension('time', 'times', invisible_count)} including non-visible text"
|
81
80
|
end
|
82
81
|
rescue # An error getting the non-visible text (if element goes out of scope) should not affect the response
|
83
82
|
end
|
@@ -90,7 +90,7 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
90
90
|
return true if string_node.disabled?
|
91
91
|
|
92
92
|
if %w[option optgroup].include? tag_name
|
93
|
-
find_xpath("parent::*[self::optgroup or self::select]")[0].disabled?
|
93
|
+
find_xpath("parent::*[self::optgroup or self::select or self::datalist]")[0].disabled?
|
94
94
|
else
|
95
95
|
!find_xpath("parent::fieldset[@disabled] | ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]").empty?
|
96
96
|
end
|
@@ -210,9 +210,7 @@ private
|
|
210
210
|
find_xpath(".//input")
|
211
211
|
end.first
|
212
212
|
|
213
|
-
|
214
|
-
labelled_control.set(!labelled_control.checked?)
|
215
|
-
end
|
213
|
+
labelled_control.set(!labelled_control.checked?) if checkbox_or_radio?(labelled_control)
|
216
214
|
end
|
217
215
|
|
218
216
|
def link?
|
@@ -229,6 +227,10 @@ private
|
|
229
227
|
|
230
228
|
protected
|
231
229
|
|
230
|
+
def checkbox_or_radio?(field = self)
|
231
|
+
field && (field.checkbox? || field.radio?)
|
232
|
+
end
|
233
|
+
|
232
234
|
def checkbox?
|
233
235
|
input_field? && type == 'checkbox'
|
234
236
|
end
|
data/lib/capybara/result.rb
CHANGED
@@ -114,7 +114,7 @@ module Capybara
|
|
114
114
|
if count.zero?
|
115
115
|
message << " but there were no matches"
|
116
116
|
else
|
117
|
-
message << ", found #{count} #{Capybara::Helpers.declension(
|
117
|
+
message << ", found #{count} #{Capybara::Helpers.declension('match', 'matches', count)}: " << full_results.map(&:text).map(&:inspect).join(", ")
|
118
118
|
end
|
119
119
|
unless rest.empty?
|
120
120
|
elements = rest.map { |el| el.text rescue "<<ERROR>>" }.map(&:inspect).join(", ")
|
data/lib/capybara/selector.rb
CHANGED
@@ -136,11 +136,19 @@ end
|
|
136
136
|
Capybara.add_selector(:link) do
|
137
137
|
xpath(:title, :alt) do |locator, href: true, enable_aria_label: false, alt: nil, title: nil, **_options|
|
138
138
|
xpath = XPath.descendant(:a)
|
139
|
-
xpath =
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
139
|
+
xpath = xpath[
|
140
|
+
case href
|
141
|
+
when nil, false
|
142
|
+
!XPath.attr(:href)
|
143
|
+
when true
|
144
|
+
XPath.attr(:href)
|
145
|
+
when Regexp
|
146
|
+
nil # needs to be handled in filter
|
147
|
+
else
|
148
|
+
XPath.attr(:href) == href.to_s
|
149
|
+
end
|
150
|
+
]
|
151
|
+
|
144
152
|
unless locator.nil?
|
145
153
|
locator = locator.to_s
|
146
154
|
matchers = [XPath.attr(:id) == locator,
|
@@ -150,20 +158,15 @@ Capybara.add_selector(:link) do
|
|
150
158
|
matchers |= XPath.attr(:'aria-label').is(locator) if enable_aria_label
|
151
159
|
xpath = xpath[matchers]
|
152
160
|
end
|
161
|
+
|
153
162
|
xpath = xpath[find_by_attr(:title, title)]
|
154
163
|
xpath = xpath[XPath.descendant(:img)[XPath.attr(:alt) == alt]] if alt
|
155
164
|
xpath
|
156
165
|
end
|
157
166
|
|
158
167
|
filter(:href) do |node, href|
|
159
|
-
|
160
|
-
|
161
|
-
true
|
162
|
-
when Regexp
|
163
|
-
node[:href].match href
|
164
|
-
else
|
165
|
-
node.first(:xpath, XPath.self[XPath.attr(:href) == href.to_s], minimum: 0)
|
166
|
-
end
|
168
|
+
# If not a Regexp it's been handled in the main XPath
|
169
|
+
href.is_a?(Regexp) ? node[:href].match(href) : true
|
167
170
|
end
|
168
171
|
|
169
172
|
describe do |**options|
|
@@ -185,7 +188,7 @@ end
|
|
185
188
|
# @filter [String] :value Matches the value of an input button
|
186
189
|
#
|
187
190
|
Capybara.add_selector(:button) do
|
188
|
-
xpath(:value, :title) do |locator, **options|
|
191
|
+
xpath(:value, :title, :type) do |locator, **options|
|
189
192
|
input_btn_xpath = XPath.descendant(:input)[XPath.attr(:type).one_of('submit', 'reset', 'image', 'button')]
|
190
193
|
btn_xpath = XPath.descendant(:button)
|
191
194
|
image_btn_xpath = XPath.descendant(:input)[XPath.attr(:type) == 'image']
|
@@ -380,10 +383,11 @@ Capybara.add_selector(:select) do
|
|
380
383
|
options.sort == actual.sort
|
381
384
|
end
|
382
385
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
386
|
+
expression_filter(:with_options) do |expr, options|
|
387
|
+
options.each do |option|
|
388
|
+
expr = expr[Capybara::Selector.all[:option].call(option)]
|
389
|
+
end
|
390
|
+
expr
|
387
391
|
end
|
388
392
|
|
389
393
|
filter(:selected) do |node, selected|
|
@@ -407,6 +411,37 @@ Capybara.add_selector(:select) do
|
|
407
411
|
end
|
408
412
|
end
|
409
413
|
|
414
|
+
Capybara.add_selector(:datalist_input) do
|
415
|
+
label "input box with datalist completion"
|
416
|
+
|
417
|
+
xpath do |locator, **options|
|
418
|
+
xpath = XPath.descendant(:input)[XPath.attr(:list)]
|
419
|
+
locate_field(xpath, locator, options)
|
420
|
+
end
|
421
|
+
|
422
|
+
filter_set(:_field, %i[disabled name placeholder])
|
423
|
+
|
424
|
+
filter(:options) do |node, options|
|
425
|
+
actual = node.find("//datalist[@id=#{node[:list]}]", visible: :all).all(:datalist_option, wait: false).map(&:value)
|
426
|
+
options.sort == actual.sort
|
427
|
+
end
|
428
|
+
|
429
|
+
expression_filter(:with_options) do |expr, options|
|
430
|
+
options.each do |option|
|
431
|
+
expr = expr[XPath.attr(:list) == XPath.anywhere(:datalist)[Capybara::Selector.all[:datalist_option].call(option)].attr(:id)]
|
432
|
+
end
|
433
|
+
expr
|
434
|
+
end
|
435
|
+
|
436
|
+
describe do |options: nil, with_options: nil, **opts|
|
437
|
+
desc = "".dup
|
438
|
+
desc << " with options #{options.inspect}" if options
|
439
|
+
desc << " with at least options #{with_options.inspect}" if with_options
|
440
|
+
desc << describe_all_expression_filters(opts)
|
441
|
+
desc
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
410
445
|
##
|
411
446
|
#
|
412
447
|
# Find option elements
|
@@ -433,6 +468,25 @@ Capybara.add_selector(:option) do
|
|
433
468
|
end
|
434
469
|
end
|
435
470
|
|
471
|
+
Capybara.add_selector(:datalist_option) do
|
472
|
+
label "datalist option"
|
473
|
+
visible(:all)
|
474
|
+
|
475
|
+
xpath do |locator|
|
476
|
+
xpath = XPath.descendant(:option)
|
477
|
+
xpath = xpath[XPath.string.n.is(locator.to_s) | (XPath.attr(:value) == locator.to_s)] unless locator.nil?
|
478
|
+
xpath
|
479
|
+
end
|
480
|
+
|
481
|
+
filter(:disabled, :boolean) { |node, value| !(value ^ node.disabled?) }
|
482
|
+
|
483
|
+
describe do |**options|
|
484
|
+
desc = "".dup
|
485
|
+
desc << " that is#{' not' unless options[:disabled]} disabled" if options.key?(:disabled)
|
486
|
+
desc
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
436
490
|
##
|
437
491
|
#
|
438
492
|
# Find file input elements
|
@@ -23,11 +23,8 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
23
23
|
::Selenium::WebDriver::Error.const_set('ElementClickInterceptedError', Class.new(::Selenium::WebDriver::Error::WebDriverError))
|
24
24
|
end
|
25
25
|
rescue LoadError => e
|
26
|
-
if e.message
|
27
|
-
|
28
|
-
else
|
29
|
-
raise e
|
30
|
-
end
|
26
|
+
raise e if e.message !~ /selenium-webdriver/
|
27
|
+
raise LoadError, "Capybara's selenium driver is unable to load `selenium-webdriver`, please install the gem and add `gem 'selenium-webdriver'` to your Gemfile if you are using bundler."
|
31
28
|
end
|
32
29
|
|
33
30
|
def browser
|
@@ -305,22 +302,27 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
305
302
|
|
306
303
|
# @api private
|
307
304
|
def firefox?
|
308
|
-
|
305
|
+
browser_name == :firefox
|
309
306
|
end
|
310
307
|
|
311
308
|
# @api private
|
312
309
|
def chrome?
|
313
|
-
|
310
|
+
browser_name == :chrome
|
314
311
|
end
|
315
312
|
|
316
313
|
# @api private
|
317
314
|
def edge?
|
318
|
-
|
315
|
+
browser_name == :edge
|
319
316
|
end
|
320
317
|
|
321
318
|
# @api private
|
322
319
|
def ie?
|
323
|
-
|
320
|
+
browser_name == :ie
|
321
|
+
end
|
322
|
+
|
323
|
+
# @api private
|
324
|
+
def browser_name
|
325
|
+
browser.browser
|
324
326
|
end
|
325
327
|
|
326
328
|
private
|
@@ -355,7 +357,7 @@ private
|
|
355
357
|
if response_text.nil?
|
356
358
|
"default_text"
|
357
359
|
else
|
358
|
-
"'#{response_text.gsub(
|
360
|
+
"'#{response_text.gsub('\\', '\\\\\\').gsub("'", "\\\\'")}'"
|
359
361
|
end
|
360
362
|
else
|
361
363
|
'null'
|
@@ -447,11 +449,8 @@ private
|
|
447
449
|
if called
|
448
450
|
execute_script('window.capybara && window.capybara.modal_handlers.shift()')
|
449
451
|
regexp = text.is_a?(Regexp) ? text : Regexp.escape(text.to_s)
|
450
|
-
if alert_text.match(regexp)
|
451
|
-
|
452
|
-
else
|
453
|
-
raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{text}" if text}"
|
454
|
-
end
|
452
|
+
raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{text}" if text}" unless alert_text.match(regexp)
|
453
|
+
alert_text
|
455
454
|
elsif called.nil?
|
456
455
|
# page changed so modal_handler data has gone away
|
457
456
|
warn "Can't verify modal text when page change occurs - ignoring" if options[:text]
|
@@ -1,19 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Capybara::Selenium::Node < Capybara::Driver::Node
|
4
|
-
SET_FORMATS = Hash.new(date: '%Y-%m-%d', time: '%H:%M', datetime: "%m%d%Y\t%I%M%P").merge(
|
5
|
-
firefox: {
|
6
|
-
date: '%Y-%m-%d',
|
7
|
-
time: '%H:%M',
|
8
|
-
datetime: "%m%d%Y\t%I%M%P"
|
9
|
-
},
|
10
|
-
chrome: {
|
11
|
-
date: '%m%d%Y',
|
12
|
-
time: '%I%M%P',
|
13
|
-
datetime: "%m%d%Y\t%I%M%P"
|
14
|
-
}
|
15
|
-
)
|
16
|
-
|
17
4
|
def visible_text
|
18
5
|
native.text
|
19
6
|
end
|
@@ -199,7 +186,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
199
186
|
parent = path.first
|
200
187
|
selector = node.tag_name
|
201
188
|
if parent
|
202
|
-
siblings = parent.find_xpath(
|
189
|
+
siblings = parent.find_xpath(selector)
|
203
190
|
selector += "[#{siblings.index(node) + 1}]" unless siblings.size == 1
|
204
191
|
end
|
205
192
|
result.push selector
|
@@ -254,27 +241,34 @@ private
|
|
254
241
|
end
|
255
242
|
|
256
243
|
def set_date(value) # rubocop:disable Naming/AccessorMethodName
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
set_text(value)
|
261
|
-
end
|
244
|
+
return set_text(value) unless value.respond_to?(:to_date)
|
245
|
+
# TODO: this would be better if locale can be detected and correct keystrokes sent
|
246
|
+
update_value_js(value.to_date.strftime('%Y-%m-%d'))
|
262
247
|
end
|
263
248
|
|
264
249
|
def set_time(value) # rubocop:disable Naming/AccessorMethodName
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
set_text(value)
|
269
|
-
end
|
250
|
+
return set_text(value) unless value.respond_to?(:to_time)
|
251
|
+
# TODO: this would be better if locale can be detected and correct keystrokes sent
|
252
|
+
update_value_js(value.to_time.strftime('%H:%M'))
|
270
253
|
end
|
271
254
|
|
272
255
|
def set_datetime_local(value) # rubocop:disable Naming/AccessorMethodName
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
256
|
+
return set_text(value) unless value.respond_to?(:to_time)
|
257
|
+
# TODO: this would be better if locale can be detected and correct keystrokes sent
|
258
|
+
update_value_js(value.to_time.strftime('%Y-%m-%dT%H:%M'))
|
259
|
+
end
|
260
|
+
|
261
|
+
def update_value_js(value)
|
262
|
+
driver.execute_script(<<-JS, self, value)
|
263
|
+
if (document.activeElement !== arguments[0]){
|
264
|
+
arguments[0].focus();
|
265
|
+
}
|
266
|
+
if (arguments[0].value != arguments[1]) {
|
267
|
+
arguments[0].value = arguments[1]
|
268
|
+
arguments[0].dispatchEvent(new InputEvent('input'));
|
269
|
+
arguments[0].dispatchEvent(new Event('change', { bubbles: true }));
|
270
|
+
}
|
271
|
+
JS
|
278
272
|
end
|
279
273
|
|
280
274
|
def set_file(value) # rubocop:disable Naming/AccessorMethodName
|