capybara 3.0.3 → 3.1.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 +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
|