mirror of
https://github.com/teamcapybara/capybara.git
synced 2022-11-09 12:08:07 -05:00
minor refactor
This commit is contained in:
parent
952d373026
commit
a6e289f6cc
3 changed files with 47 additions and 43 deletions
|
@ -174,41 +174,12 @@ module Capybara
|
||||||
#
|
#
|
||||||
# @return [Capybara::Node::Element] The option element selected
|
# @return [Capybara::Node::Element] The option element selected
|
||||||
def select(value = nil, from: nil, **options)
|
def select(value = nil, from: nil, **options)
|
||||||
scope = if from
|
el = from ? find_select_or_datalist_input(from, options) : self
|
||||||
synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
|
|
||||||
begin
|
|
||||||
find(:select, from, options)
|
|
||||||
rescue Capybara::ElementNotFound => select_error
|
|
||||||
raise if %i[selected with_selected multiple].any? { |option| options.key?(option) }
|
|
||||||
begin
|
|
||||||
find(:datalist_input, from, options)
|
|
||||||
rescue Capybara::ElementNotFound => dlinput_error
|
|
||||||
raise Capybara::ElementNotFound, "#{select_error.message} and #{dlinput_error.message}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
if scope.respond_to?(:tag_name) && scope.tag_name == "input"
|
if el.respond_to?(:tag_name) && (el.tag_name == "input")
|
||||||
begin
|
select_datalist_option(el, value)
|
||||||
# TODO: this is a more efficient but won't work with non-JS drivers
|
|
||||||
# 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)
|
|
||||||
datalist_options = session.evaluate_script(DATALIST_OPTIONS_SCRIPT, scope)
|
|
||||||
if (option = datalist_options.find { |o| o['value'] == value || o['label'] == value })
|
|
||||||
scope.set(option["value"])
|
|
||||||
else
|
|
||||||
raise ::Capybara::ElementNotFound, "Unable to find datalist option \"#{value}\""
|
|
||||||
end
|
|
||||||
rescue ::Capybara::NotSupportedByDriverError
|
|
||||||
# Implement for drivers that don't support JS
|
|
||||||
datalist = find(:xpath, XPath.descendant(:datalist)[XPath.attr(:id) == scope[:list]], visible: false)
|
|
||||||
option = datalist.find(:datalist_option, value, disabled: false)
|
|
||||||
scope.set(option.value)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
scope.find(:option, value, options).select_option
|
el.find(:option, value, options).select_option
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -267,6 +238,35 @@ module Capybara
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def find_select_or_datalist_input(from, options)
|
||||||
|
synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
|
||||||
|
begin
|
||||||
|
find(:select, from, options)
|
||||||
|
rescue Capybara::ElementNotFound => select_error
|
||||||
|
raise if %i[selected with_selected multiple].any? { |option| options.key?(option) }
|
||||||
|
begin
|
||||||
|
find(:datalist_input, from, options)
|
||||||
|
rescue Capybara::ElementNotFound => dlinput_error
|
||||||
|
raise Capybara::ElementNotFound, "#{select_error.message} and #{dlinput_error.message}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def select_datalist_option(input, value)
|
||||||
|
datalist_options = session.evaluate_script(DATALIST_OPTIONS_SCRIPT, input)
|
||||||
|
if (option = datalist_options.find { |o| o['value'] == value || o['label'] == value })
|
||||||
|
input.set(option["value"])
|
||||||
|
else
|
||||||
|
raise ::Capybara::ElementNotFound, "Unable to find datalist option \"#{value}\""
|
||||||
|
end
|
||||||
|
rescue ::Capybara::NotSupportedByDriverError
|
||||||
|
# Implement for drivers that don't support JS
|
||||||
|
datalist = find(:xpath, XPath.descendant(:datalist)[XPath.attr(:id) == input[:list]], visible: false)
|
||||||
|
option = datalist.find(:datalist_option, value, disabled: false)
|
||||||
|
input.set(option.value)
|
||||||
|
end
|
||||||
|
|
||||||
def while_visible(element, visible_css)
|
def while_visible(element, visible_css)
|
||||||
visible_css = { opacity: 1, display: 'block', visibility: 'visible' } if visible_css == true
|
visible_css = { opacity: 1, display: 'block', visibility: 'visible' } if visible_css == true
|
||||||
_update_style(element, visible_css)
|
_update_style(element, visible_css)
|
||||||
|
|
|
@ -245,7 +245,7 @@ module Capybara
|
||||||
minimum_specified = options_include_minimum?(options)
|
minimum_specified = options_include_minimum?(options)
|
||||||
options = { minimum: 1 }.merge(options) unless minimum_specified
|
options = { minimum: 1 }.merge(options) unless minimum_specified
|
||||||
options[:session_options] = session_options
|
options[:session_options] = session_options
|
||||||
query = Capybara::Queries::SelectorQuery.new(*args.push(options), &optional_filter_block)
|
query = Capybara::Queries::SelectorQuery.new(*args, options, &optional_filter_block)
|
||||||
result = nil
|
result = nil
|
||||||
begin
|
begin
|
||||||
synchronize(query.wait) do
|
synchronize(query.wait) do
|
||||||
|
@ -298,11 +298,11 @@ module Capybara
|
||||||
end
|
end
|
||||||
|
|
||||||
def ambiguous?(query, result)
|
def ambiguous?(query, result)
|
||||||
((query.match == :one) || (query.match == :smart)) && (result.size > 1)
|
%i[one smart].include?(query.match) && (result.size > 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
def prefer_exact?(query)
|
def prefer_exact?(query)
|
||||||
(query.match == :smart) || (query.match == :prefer_exact)
|
%i[smart prefer_exact].include?(query.match)
|
||||||
end
|
end
|
||||||
|
|
||||||
def options_include_minimum?(opts)
|
def options_include_minimum?(opts)
|
||||||
|
|
|
@ -93,11 +93,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
if e.is_a?(::Selenium::WebDriver::Error::ElementClickInterceptedError) ||
|
if e.is_a?(::Selenium::WebDriver::Error::ElementClickInterceptedError) ||
|
||||||
e.message =~ /Other element would receive the click/
|
e.message =~ /Other element would receive the click/
|
||||||
begin
|
scroll_to_center
|
||||||
driver.execute_script("arguments[0].scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'})", self)
|
|
||||||
rescue StandardError # rubocop:disable Lint/HandleExceptions
|
|
||||||
# Swallow error if scrollIntoView with options isn't supported
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
raise e
|
raise e
|
||||||
end
|
end
|
||||||
|
@ -230,6 +226,11 @@ private
|
||||||
def scroll_if_needed
|
def scroll_if_needed
|
||||||
yield
|
yield
|
||||||
rescue ::Selenium::WebDriver::Error::MoveTargetOutOfBoundsError
|
rescue ::Selenium::WebDriver::Error::MoveTargetOutOfBoundsError
|
||||||
|
scroll_to_center
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
|
||||||
|
def scroll_to_center
|
||||||
script = <<-'JS'
|
script = <<-'JS'
|
||||||
try {
|
try {
|
||||||
arguments[0].scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'});
|
arguments[0].scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'});
|
||||||
|
@ -237,8 +238,11 @@ private
|
||||||
arguments[0].scrollIntoView(true);
|
arguments[0].scrollIntoView(true);
|
||||||
}
|
}
|
||||||
JS
|
JS
|
||||||
driver.execute_script(script, self)
|
begin
|
||||||
yield
|
driver.execute_script(script, self)
|
||||||
|
rescue StandardError # rubocop:disable Lint/HandleExceptions
|
||||||
|
# Swallow error if scrollIntoView with options isn't supported
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_date(value) # rubocop:disable Naming/AccessorMethodName
|
def set_date(value) # rubocop:disable Naming/AccessorMethodName
|
||||||
|
|
Loading…
Reference in a new issue