mirror of
https://github.com/teamcapybara/capybara.git
synced 2022-11-09 12:08:07 -05:00
Code cleanup and enable line length cop
This commit is contained in:
parent
0685c3902f
commit
f6b2f3adf0
27 changed files with 173 additions and 91 deletions
|
@ -15,11 +15,11 @@ Metrics/LineLength:
|
|||
Exclude:
|
||||
- 'spec/**/*'
|
||||
- 'lib/capybara/spec/**/*'
|
||||
- 'lib/capybara/selector.rb'
|
||||
IgnoredPatterns:
|
||||
- '\s*# '
|
||||
- '\s*(raise|warn) '
|
||||
Max: 120
|
||||
Enabled: false
|
||||
|
||||
Metrics/BlockLength:
|
||||
Exclude:
|
||||
|
|
|
@ -460,7 +460,8 @@ end
|
|||
|
||||
Capybara.register_server :webrick do |app, port, host, **options|
|
||||
require 'rack/handler/webrick'
|
||||
Rack::Handler::WEBrick.run(app, { Host: host, Port: port, AccessLog: [], Logger: WEBrick::Log.new(nil, 0) }.merge(options))
|
||||
options = { Host: host, Port: port, AccessLog: [], Logger: WEBrick::Log.new(nil, 0) }.merge(options)
|
||||
Rack::Handler::WEBrick.run(app, options)
|
||||
end
|
||||
|
||||
Capybara.register_server :puma do |app, port, host, **options|
|
||||
|
@ -476,8 +477,8 @@ Capybara.register_server :puma do |app, port, host, **options|
|
|||
# If we just run the Puma Rack handler it installs signal handlers which prevent us from being able to interrupt tests.
|
||||
# Therefore construct and run the Server instance ourselves.
|
||||
# Rack::Handler::Puma.run(app, { Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false }.merge(options))
|
||||
|
||||
conf = Rack::Handler::Puma.config(app, { Host: host, Port: port, Threads: '0:4', workers: 0, daemon: false }.merge(options))
|
||||
options = { Host: host, Port: port, Threads: '0:4', workers: 0, daemon: false }.merge(options)
|
||||
conf = Rack::Handler::Puma.config(app, options)
|
||||
events = conf.options[:Silent] ? ::Puma::Events.strings : ::Puma::Events.stdio
|
||||
|
||||
events.log 'Capybara starting Puma...'
|
||||
|
|
|
@ -42,12 +42,12 @@ module Capybara
|
|||
# @!method assert_no_current_path
|
||||
# see {Capybara::SessionMatchers#assert_no_current_path}
|
||||
|
||||
%w[assert_text assert_no_text assert_title assert_no_title assert_current_path assert_no_current_path].each do |assertion_name|
|
||||
%w[text no_text title no_title current_path no_current_path].each do |assertion_name|
|
||||
class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
|
||||
def #{assertion_name} *args
|
||||
def assert_#{assertion_name} *args
|
||||
self.assertions +=1
|
||||
subject, args = determine_subject(args)
|
||||
subject.#{assertion_name}(*args)
|
||||
subject.assert_#{assertion_name}(*args)
|
||||
rescue Capybara::ExpectationNotMet => e
|
||||
raise ::Minitest::Assertion, e.message
|
||||
end
|
||||
|
@ -86,15 +86,14 @@ module Capybara
|
|||
# @!method assert_style
|
||||
# see {Capybara::Node::Matchers#assert_style}
|
||||
|
||||
%w[assert_selector assert_no_selector
|
||||
assert_all_of_selectors assert_none_of_selectors assert_any_of_selectors
|
||||
assert_matches_selector assert_not_matches_selector
|
||||
assert_style].each do |assertion_name|
|
||||
%w[selector no_selector style
|
||||
all_of_selectors none_of_selectors any_of_selectors
|
||||
matches_selector not_matches_selector].each do |assertion_name|
|
||||
class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
|
||||
def #{assertion_name} *args, &optional_filter_block
|
||||
def assert_#{assertion_name} *args, &optional_filter_block
|
||||
self.assertions +=1
|
||||
subject, args = determine_subject(args)
|
||||
subject.#{assertion_name}(*args, &optional_filter_block)
|
||||
subject.assert_#{assertion_name}(*args, &optional_filter_block)
|
||||
rescue Capybara::ExpectationNotMet => e
|
||||
raise ::Minitest::Assertion, e.message
|
||||
end
|
||||
|
|
|
@ -322,7 +322,8 @@ module Capybara
|
|||
rescue StandardError # rubocop:disable Lint/HandleExceptions swallow extra errors
|
||||
end
|
||||
|
||||
def _check_with_label(selector, checked, locator, allow_label_click: session_options.automatic_label_click, **options)
|
||||
def _check_with_label(selector, checked, locator,
|
||||
allow_label_click: session_options.automatic_label_click, **options)
|
||||
options[:allow_self] = true if locator.nil?
|
||||
|
||||
synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
|
||||
|
|
|
@ -100,9 +100,7 @@ module Capybara
|
|||
#
|
||||
def assert_selector(*args, &optional_filter_block)
|
||||
_verify_selector_result(args, optional_filter_block) do |result, query|
|
||||
unless result.matches_count? && (result.any? || query.expects_none?)
|
||||
raise Capybara::ExpectationNotMet, result.failure_message
|
||||
end
|
||||
raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count? && (result.any? || query.expects_none?)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -104,10 +104,11 @@ module Capybara
|
|||
return false if (tag_name == 'input') && (native[:type] == 'hidden')
|
||||
|
||||
if check_ancestors
|
||||
!find_xpath("boolean(./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or @hidden or name()='script' or name()='head'])")
|
||||
!find_xpath(VISIBILITY_XPATH)
|
||||
# !find_xpath("boolean(./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or @hidden or name()='script' or name()='head'])")
|
||||
else
|
||||
# No need for an xpath if only checking the current element
|
||||
!(native.has_attribute?('hidden') || (native[:style] =~ /display:\s?none/) || %w[script head].include?(tag_name))
|
||||
!(native.key?('hidden') || (native[:style] =~ /display:\s?none/) || %w[script head].include?(tag_name))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -185,6 +186,14 @@ module Capybara
|
|||
|
||||
option[:value] || option.content
|
||||
end
|
||||
|
||||
VISIBILITY_XPATH = XPath.generate do |x|
|
||||
x.ancestor_or_self[
|
||||
x.attr(:style)[x.contains('display:none') | x.contains('display: none')] |
|
||||
x.attr(:hidden) |
|
||||
x.qname.one_of('script', 'head')
|
||||
].boolean
|
||||
end.to_s.freeze
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -77,17 +77,21 @@ module Capybara
|
|||
message = +''
|
||||
count, between, maximum, minimum = options.values_at(:count, :between, :maximum, :minimum)
|
||||
if count
|
||||
message << " #{count} #{Capybara::Helpers.declension('time', 'times', count)}"
|
||||
message << " #{occurrences count}"
|
||||
elsif between
|
||||
message << " between #{between.first} and #{between.last} times"
|
||||
elsif maximum
|
||||
message << " at most #{maximum} #{Capybara::Helpers.declension('time', 'times', maximum)}"
|
||||
message << " at most #{occurrences maximum}"
|
||||
elsif minimum
|
||||
message << " at least #{minimum} #{Capybara::Helpers.declension('time', 'times', minimum)}"
|
||||
message << " at least #{occurrences minimum}"
|
||||
end
|
||||
message
|
||||
end
|
||||
|
||||
def occurrences(count)
|
||||
"#{count} #{Capybara::Helpers.declension('time', 'times', count)}"
|
||||
end
|
||||
|
||||
def assert_valid_keys
|
||||
invalid_keys = @options.keys - valid_keys
|
||||
return if invalid_keys.empty?
|
||||
|
|
|
@ -24,7 +24,8 @@ module Capybara
|
|||
|
||||
raise ArgumentError, "Unused parameters passed to #{self.class.name} : #{args}" unless args.empty?
|
||||
|
||||
@expression = selector.call(@locator, @options.merge(selector_config: { enable_aria_label: enable_aria_label, test_id: test_id }))
|
||||
selector_config = { enable_aria_label: enable_aria_label, test_id: test_id }
|
||||
@expression = selector.call(@locator, @options.merge(selector_config: selector_config))
|
||||
|
||||
warn_exact_usage
|
||||
|
||||
|
@ -34,21 +35,23 @@ module Capybara
|
|||
def name; selector.name; end
|
||||
def label; selector.label || selector.name; end
|
||||
|
||||
def description(applied = false)
|
||||
def description(only_applied = false)
|
||||
desc = +''
|
||||
if !applied || applied_filters
|
||||
show_for = show_for_stage(only_applied)
|
||||
|
||||
if show_for[:any]
|
||||
desc << 'visible ' if visible == :visible
|
||||
desc << 'non-visible ' if visible == :hidden
|
||||
end
|
||||
desc << "#{label} #{locator.inspect}"
|
||||
if !applied || applied_filters
|
||||
if show_for[:any]
|
||||
desc << " with#{' exact' if exact_text == true} text #{options[:text].inspect}" if options[:text]
|
||||
desc << " with exact text #{exact_text}" if exact_text.is_a?(String)
|
||||
end
|
||||
desc << " with id #{options[:id]}" if options[:id]
|
||||
desc << " with classes [#{Array(options[:class]).join(',')}]" if options[:class]
|
||||
desc << selector.description(node_filters: !applied || (applied_filters == :node), **options)
|
||||
desc << ' that also matches the custom filter block' if @filter_block && (!applied || (applied_filters == :node))
|
||||
desc << selector.description(node_filters: show_for[:node], **options)
|
||||
desc << ' that also matches the custom filter block' if @filter_block && show_for[:node]
|
||||
desc << " within #{@resolved_node.inspect}" if describe_within?
|
||||
desc
|
||||
end
|
||||
|
@ -60,17 +63,17 @@ module Capybara
|
|||
def matches_filters?(node)
|
||||
return true if (@resolved_node&.== node) && options[:allow_self]
|
||||
|
||||
@applied_filters ||= :system
|
||||
applied_filters << :system
|
||||
return false unless matches_system_filters?(node)
|
||||
|
||||
@applied_filters = :node
|
||||
applied_filters << :node
|
||||
matches_node_filters?(node) && matches_filter_block?(node)
|
||||
rescue *(node.respond_to?(:session) ? node.session.driver.invalid_element_errors : [])
|
||||
false
|
||||
end
|
||||
|
||||
def visible
|
||||
case (vis = options.fetch(:visible) { @selector.default_visibility(session_options.ignore_hidden_elements, options) })
|
||||
case (vis = options.fetch(:visible) { default_visibility })
|
||||
when true then :visible
|
||||
when false then :all
|
||||
else vis
|
||||
|
@ -98,7 +101,7 @@ module Capybara
|
|||
|
||||
# @api private
|
||||
def resolve_for(node, exact = nil)
|
||||
@applied_filters = false
|
||||
applied_filters.clear
|
||||
@resolved_node = node
|
||||
node.synchronize do
|
||||
children = find_nodes_by_selector_format(node, exact).map(&method(:to_element))
|
||||
|
@ -121,8 +124,14 @@ module Capybara
|
|||
|
||||
private
|
||||
|
||||
def show_for_stage(only_applied)
|
||||
lambda do |stage = :any|
|
||||
!only_applied || (stage == :any ? applied_filters.any? : applied_filters.include?(stage))
|
||||
end
|
||||
end
|
||||
|
||||
def applied_filters
|
||||
@applied_filters ||= false
|
||||
@applied_filters ||= []
|
||||
end
|
||||
|
||||
def find_selector(locator)
|
||||
|
@ -183,17 +192,21 @@ module Capybara
|
|||
end
|
||||
end
|
||||
|
||||
def filter_set(name)
|
||||
::Capybara::Selector::FilterSet.all[name]
|
||||
end
|
||||
|
||||
def node_filters
|
||||
if options.key?(:filter_set)
|
||||
::Capybara::Selector::FilterSet.all[options[:filter_set]].node_filters
|
||||
filter_set(options[:filter_set])
|
||||
else
|
||||
@selector.node_filters
|
||||
end
|
||||
@selector
|
||||
end.node_filters
|
||||
end
|
||||
|
||||
def expression_filters
|
||||
filters = @selector.expression_filters
|
||||
filters.merge ::Capybara::Selector::FilterSet.all[options[:filter_set]].expression_filters if options.key?(:filter_set)
|
||||
filters.merge filter_set(options[:filter_set]).expression_filters if options.key?(:filter_set)
|
||||
filters
|
||||
end
|
||||
|
||||
|
@ -253,7 +266,7 @@ module Capybara
|
|||
unapplied_options = options.keys - valid_keys
|
||||
expression_filters.inject(expression) do |expr, (name, ef)|
|
||||
if ef.matcher?
|
||||
unapplied_options.select { |option_name| ef.handles_option?(option_name) }.inject(expr) do |memo, option_name|
|
||||
unapplied_options.select(&ef.method(:handles_option?)).inject(expr) do |memo, option_name|
|
||||
unapplied_options.delete(option_name)
|
||||
ef.apply_filter(memo, option_name, options[option_name])
|
||||
end
|
||||
|
@ -348,6 +361,10 @@ module Capybara
|
|||
!!node.text(text_visible, normalize_ws: normalize_ws).match(regexp)
|
||||
end
|
||||
|
||||
def default_visibility
|
||||
@selector.default_visibility(session_options.ignore_hidden_elements, options)
|
||||
end
|
||||
|
||||
def builder
|
||||
selector.builder
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ module Capybara
|
|||
module Queries
|
||||
class StyleQuery < BaseQuery
|
||||
def initialize(expected_styles, session_options:, **options)
|
||||
@expected_styles = expected_styles.each_with_object({}) { |(style, value), str_keys| str_keys[style.to_s] = value }
|
||||
@expected_styles = stringify_keys(expected_styles)
|
||||
@options = options
|
||||
@actual_styles = {}
|
||||
super(@options)
|
||||
|
@ -33,6 +33,10 @@ module Capybara
|
|||
|
||||
private
|
||||
|
||||
def stringify_keys(hsh)
|
||||
hsh.each_with_object({}) { |(k, v), str_keys| str_keys[k.to_s] = v }
|
||||
end
|
||||
|
||||
def valid_keys
|
||||
%i[wait]
|
||||
end
|
||||
|
|
|
@ -65,7 +65,7 @@ module Capybara
|
|||
insensitive_count = @actual_text.scan(insensitive_regexp).size
|
||||
return if insensitive_count == @count
|
||||
|
||||
"it was found #{insensitive_count} #{Capybara::Helpers.declension('time', 'times', insensitive_count)} using a case insensitive search"
|
||||
"it was found #{occurrences insensitive_count} using a case insensitive search"
|
||||
end
|
||||
|
||||
def invisible_message
|
||||
|
@ -73,7 +73,7 @@ module Capybara
|
|||
invisible_count = invisible_text.scan(@search_regexp).size
|
||||
return if invisible_count == @count
|
||||
|
||||
"it was found #{invisible_count} #{Capybara::Helpers.declension('time', 'times', invisible_count)} including non-visible text"
|
||||
"it was found #{occurrences invisible_count} including non-visible text"
|
||||
rescue StandardError
|
||||
# An error getting the non-visible text (if element goes out of scope) should not affect the response
|
||||
nil
|
||||
|
|
|
@ -8,7 +8,7 @@ module Capybara
|
|||
@expected_title = expected_title.is_a?(Regexp) ? expected_title : expected_title.to_s
|
||||
@options = options
|
||||
super(@options)
|
||||
@search_regexp = Capybara::Helpers.to_regexp(@expected_title, all_whitespace: true, exact: options.fetch(:exact, false))
|
||||
@search_regexp = Helpers.to_regexp(@expected_title, all_whitespace: true, exact: options.fetch(:exact, false))
|
||||
assert_valid_keys
|
||||
end
|
||||
|
||||
|
|
|
@ -96,9 +96,11 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
|
|||
return true if string_node.disabled?
|
||||
|
||||
if %w[option optgroup].include? tag_name
|
||||
find_xpath('parent::*[self::optgroup or self::select or self::datalist]')[0].disabled?
|
||||
find_xpath(OPTION_OWNER_XPATH)[0].disabled?
|
||||
# find_xpath('parent::*[self::optgroup or self::select or self::datalist]')[0].disabled?
|
||||
else
|
||||
!find_xpath('parent::fieldset[@disabled] | ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]').empty?
|
||||
!find_xpath(DISABLED_BY_FIELDSET_XPATH).empty?
|
||||
# !find_xpath('parent::fieldset[@disabled] | ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]').empty?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -256,4 +258,18 @@ protected
|
|||
def textarea?
|
||||
tag_name == 'textarea'
|
||||
end
|
||||
|
||||
OPTION_OWNER_XPATH = XPath.parent(:optgroup, :select, :datalist).to_s.freeze
|
||||
DISABLED_BY_FIELDSET_XPATH = XPath.generate do |x|
|
||||
x.parent(:fieldset)[
|
||||
XPath.attr(:disabled)
|
||||
] + x.ancestor[
|
||||
~x.self(:legend) |
|
||||
x.preceding_sibling(:legend)
|
||||
][
|
||||
x.parent(:fieldset)[
|
||||
x.attr(:disabled)
|
||||
]
|
||||
]
|
||||
end.to_s.freeze
|
||||
end
|
||||
|
|
|
@ -108,7 +108,8 @@ module Capybara
|
|||
if count.zero?
|
||||
message << ' but there were no matches'
|
||||
else
|
||||
message << ", found #{count} #{Capybara::Helpers.declension('match', 'matches', count)}: " << full_results.map(&:text).map(&:inspect).join(', ')
|
||||
message << ", found #{count} #{Capybara::Helpers.declension('match', 'matches', count)}: " \
|
||||
<< full_results.map(&:text).map(&:inspect).join(', ')
|
||||
end
|
||||
unless rest.empty?
|
||||
elements = rest.map { |el| el.text rescue '<<ERROR>>' }.map(&:inspect).join(', ') # rubocop:disable Style/RescueModifier
|
||||
|
|
|
@ -14,10 +14,10 @@ RSpec.configure do |config|
|
|||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.alias_example_group_to :feature, capybara_feature: true, type: :feature
|
||||
config.alias_example_group_to :xfeature, capybara_feature: true, type: :feature, skip: 'Temporarily disabled with xfeature'
|
||||
config.alias_example_group_to :ffeature, capybara_feature: true, type: :feature, focus: true
|
||||
config.alias_example_group_to :feature, :capybara_feature, type: :feature
|
||||
config.alias_example_group_to :xfeature, :capybara_feature, type: :feature, skip: 'Temporarily disabled with xfeature'
|
||||
config.alias_example_group_to :ffeature, :capybara_feature, :focus, type: :feature
|
||||
config.alias_example_to :scenario
|
||||
config.alias_example_to :xscenario, skip: 'Temporarily disabled with xscenario'
|
||||
config.alias_example_to :fscenario, focus: true
|
||||
config.alias_example_to :fscenario, :focus
|
||||
end
|
||||
|
|
|
@ -27,7 +27,9 @@ if RUBY_ENGINE == 'jruby'
|
|||
|
||||
def included(base)
|
||||
warn 'including Capybara::DSL in the global scope is not recommended!' if base == Object
|
||||
base.send(:include, ::Capybara::RSpecMatcherProxies) if defined?(::RSpec::Matchers) && base.include?(::RSpec::Matchers)
|
||||
if defined?(::RSpec::Matchers) && base.include?(::RSpec::Matchers)
|
||||
base.send(:include, ::Capybara::RSpecMatcherProxies)
|
||||
end
|
||||
super
|
||||
end
|
||||
end
|
||||
|
|
|
@ -129,7 +129,8 @@ module Capybara
|
|||
Matchers::HaveStyle.new(styles, options)
|
||||
end
|
||||
|
||||
%w[selector css xpath text title current_path link button field checked_field unchecked_field select table].each do |matcher_type|
|
||||
%w[selector css xpath text title current_path link button
|
||||
field checked_field unchecked_field select table].each do |matcher_type|
|
||||
define_method "have_no_#{matcher_type}" do |*args, &optional_filter_block|
|
||||
Matchers::NegatedMatcher.new(send("have_#{matcher_type}", *args, &optional_filter_block))
|
||||
end
|
||||
|
|
|
@ -278,7 +278,7 @@ Capybara.add_selector(:select) do
|
|||
|
||||
expression_filter(:with_options) do |expr, options|
|
||||
options.inject(expr) do |xpath, option|
|
||||
xpath[Capybara::Selector.all[:option].call(option)]
|
||||
xpath[self.class.all[:option].call(option)]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -325,7 +325,7 @@ Capybara.add_selector(:datalist_input) do
|
|||
|
||||
expression_filter(:with_options) do |expr, options|
|
||||
options.inject(expr) do |xpath, option|
|
||||
xpath[XPath.attr(:list) == XPath.anywhere(:datalist)[Capybara::Selector.all[:datalist_option].call(option)].attr(:id)]
|
||||
xpath[XPath.attr(:list) == XPath.anywhere(:datalist)[self.class.all[:datalist_option].call(option)].attr(:id)]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -21,11 +21,11 @@ module Capybara
|
|||
end
|
||||
|
||||
S = '\u{80}-\u{D7FF}\u{E000}-\u{FFFD}\u{10000}-\u{10FFFF}'
|
||||
H = /[0-9a-fA-F]/
|
||||
UNICODE = /\\#{H}{1,6}[ \t\r\n\f]?/
|
||||
NONASCII = /[#{S}]/
|
||||
ESCAPE = /#{UNICODE}|\\[ -~#{S}]/
|
||||
NMSTART = /[_a-zA-Z]|#{NONASCII}|#{ESCAPE}/
|
||||
H = /[0-9a-fA-F]/.freeze
|
||||
UNICODE = /\\#{H}{1,6}[ \t\r\n\f]?/.freeze
|
||||
NONASCII = /[#{S}]/.freeze
|
||||
ESCAPE = /#{UNICODE}|\\[ -~#{S}]/.freeze
|
||||
NMSTART = /[_a-zA-Z]|#{NONASCII}|#{ESCAPE}/.freeze
|
||||
|
||||
class Splitter
|
||||
def split(css)
|
||||
|
|
|
@ -430,15 +430,19 @@ module Capybara
|
|||
def describe_all_expression_filters(**opts)
|
||||
expression_filters.map do |ef_name, ef|
|
||||
if ef.matcher?
|
||||
opts.keys.map do |key|
|
||||
" with #{ef_name}[#{key} => #{opts[key]}]" if ef.handles_option?(key) && !::Capybara::Queries::SelectorQuery::VALID_KEYS.include?(key)
|
||||
end.join
|
||||
handled_custom_keys(ef, opts.keys).map { |key| " with #{ef_name}[#{key} => #{opts[key]}]" }.join
|
||||
elsif opts.key?(ef_name)
|
||||
" with #{ef_name} #{opts[ef_name]}"
|
||||
end
|
||||
end.join
|
||||
end
|
||||
|
||||
def handled_custom_keys(filter, keys)
|
||||
keys.select do |key|
|
||||
filter.handles_option?(key) && !::Capybara::Queries::SelectorQuery::VALID_KEYS.include?(key)
|
||||
end
|
||||
end
|
||||
|
||||
def find_by_attr(attribute, value)
|
||||
finder_name = "find_by_#{attribute}_attr"
|
||||
if respond_to?(finder_name, true)
|
||||
|
|
|
@ -352,11 +352,15 @@ private
|
|||
when :chrome
|
||||
extend ChromeDriver
|
||||
when :firefox
|
||||
require 'capybara/selenium/patches/pause_duration_fix' if sel_driver.capabilities['moz:geckodriverVersion']&.start_with?('0.22.')
|
||||
require 'capybara/selenium/patches/pause_duration_fix' if pause_broken?(sel_driver)
|
||||
extend MarionetteDriver if sel_driver.capabilities.is_a?(::Selenium::WebDriver::Remote::W3C::Capabilities)
|
||||
end
|
||||
end
|
||||
|
||||
def pause_broken?(driver)
|
||||
driver.capabilities['moz:geckodriverVersion']&.start_with?('0.22.')
|
||||
end
|
||||
|
||||
def setup_exit_handler
|
||||
main = Process.pid
|
||||
at_exit do
|
||||
|
|
|
@ -170,22 +170,9 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|||
selector = node[:tagName]
|
||||
if node[:namespaceURI] != default_ns
|
||||
selector = XPath.child.where((XPath.local_name == selector) & (XPath.namespace_uri == node[:namespaceURI])).to_s
|
||||
selector
|
||||
end
|
||||
|
||||
if parent
|
||||
siblings = parent.find_xpath(selector)
|
||||
selector += case siblings.size
|
||||
when 0
|
||||
'[ERROR]' # IE doesn't support full XPath (namespace-uri, etc)
|
||||
when 1
|
||||
'' # index not necessary when only one matching element
|
||||
else
|
||||
idx = siblings.index(node)
|
||||
# Element may not be found in the siblings if it has gone away
|
||||
idx.nil? ? '[ERROR]' : "[#{idx + 1}]"
|
||||
end
|
||||
end
|
||||
selector += sibling_index(parent, node, selector) if parent
|
||||
result.push selector
|
||||
end
|
||||
|
||||
|
@ -203,6 +190,20 @@ protected
|
|||
|
||||
private
|
||||
|
||||
def sibling_index(parent, node, selector)
|
||||
siblings = parent.find_xpath(selector)
|
||||
case siblings.size
|
||||
when 0
|
||||
'[ERROR]' # IE doesn't support full XPath (namespace-uri, etc)
|
||||
when 1
|
||||
'' # index not necessary when only one matching element
|
||||
else
|
||||
idx = siblings.index(node)
|
||||
# Element may not be found in the siblings if it has gone away
|
||||
idx.nil? ? '[ERROR]' : "[#{idx + 1}]"
|
||||
end
|
||||
end
|
||||
|
||||
def boolean_attr(val)
|
||||
val && (val != 'false')
|
||||
end
|
||||
|
|
|
@ -9,8 +9,9 @@ class Capybara::Selenium::MarionetteNode < Capybara::Selenium::Node
|
|||
super
|
||||
rescue ::Selenium::WebDriver::Error::ElementNotInteractableError
|
||||
if tag_name == 'tr'
|
||||
warn 'You are attempting to click a table row which has issues in geckodriver/marionette - see https://github.com/mozilla/geckodriver/issues/1228. ' \
|
||||
'Your test should probably be clicking on a table cell like a user would. Clicking the first cell in the row instead.'
|
||||
warn 'You are attempting to click a table row which has issues in geckodriver/marionette - '\
|
||||
'see https://github.com/mozilla/geckodriver/issues/1228. Your test should probably be '\
|
||||
'clicking on a table cell like a user would. Clicking the first cell in the row instead.'
|
||||
return find_css('th:first-child,td:first-child')[0].click(keys, options)
|
||||
end
|
||||
raise
|
||||
|
@ -26,7 +27,8 @@ class Capybara::Selenium::MarionetteNode < Capybara::Selenium::Node
|
|||
if %w[option optgroup].include? tag_name
|
||||
find_xpath('parent::*[self::optgroup or self::select]')[0].disabled?
|
||||
else
|
||||
!find_xpath('parent::fieldset[@disabled] | ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]').empty?
|
||||
!find_xpath(DISABLED_BY_FIELDSET_XPATH).empty?
|
||||
# !find_xpath('parent::fieldset[@disabled] | ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]').empty?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -99,14 +101,27 @@ private
|
|||
return nil unless local_file
|
||||
raise ArgumentError, "You may only upload files: #{local_file.inspect}" unless File.file?(local_file)
|
||||
|
||||
result = bridge.http.call(:post, "session/#{bridge.session_id}/file", file: Selenium::WebDriver::Zipper.zip_file(local_file))
|
||||
result['value']
|
||||
file = ::Selenium::WebDriver::Zipper.zip_file(local_file)
|
||||
bridge.http.call(:post, "session/#{bridge.session_id}/file", file: file)['value']
|
||||
end
|
||||
|
||||
def browser_version
|
||||
driver.browser.capabilities[:browser_version].to_f
|
||||
end
|
||||
|
||||
DISABLED_BY_FIELDSET_XPATH = XPath.generate do |x|
|
||||
x.parent(:fieldset)[
|
||||
x.attr(:disabled)
|
||||
] + x.ancestor[
|
||||
~x.self(:legned) |
|
||||
x.preceding_sibling(:legend)
|
||||
][
|
||||
x.parent(:fieldset)[
|
||||
x.attr(:disabled)
|
||||
]
|
||||
]
|
||||
end.to_s.freeze
|
||||
|
||||
class ModifierKeysStack
|
||||
def initialize
|
||||
@stack = []
|
||||
|
|
|
@ -6,6 +6,4 @@ module PauseDurationFix
|
|||
end
|
||||
end
|
||||
|
||||
if defined?(::Selenium::WebDriver::Interactions::Pause)
|
||||
::Selenium::WebDriver::Interactions::Pause.prepend PauseDurationFix
|
||||
end
|
||||
::Selenium::WebDriver::Interactions::Pause.prepend PauseDurationFix
|
||||
|
|
|
@ -18,7 +18,12 @@ module Capybara
|
|||
|
||||
attr_reader :app, :port, :host
|
||||
|
||||
def initialize(app, *deprecated_options, port: Capybara.server_port, host: Capybara.server_host, reportable_errors: Capybara.server_errors, extra_middleware: [])
|
||||
def initialize(app,
|
||||
*deprecated_options,
|
||||
port: Capybara.server_port,
|
||||
host: Capybara.server_host,
|
||||
reportable_errors: Capybara.server_errors,
|
||||
extra_middleware: [])
|
||||
warn 'Positional arguments, other than the application, to Server#new are deprecated, please use keyword arguments' unless deprecated_options.empty?
|
||||
@app = app
|
||||
@extra_middleware = extra_middleware
|
||||
|
|
|
@ -16,7 +16,7 @@ module Capybara
|
|||
|
||||
def initialize(app)
|
||||
@app = app
|
||||
@disable_markup = format(DISABLE_MARKUP_TEMPLATE, selector: AnimationDisabler.selector_for(Capybara.disable_animation))
|
||||
@disable_markup = format(DISABLE_MARKUP_TEMPLATE, selector: self.class.selector_for(Capybara.disable_animation))
|
||||
end
|
||||
|
||||
def call(env)
|
||||
|
|
|
@ -819,7 +819,9 @@ module Capybara
|
|||
end
|
||||
|
||||
def prepare_path(path, extension)
|
||||
File.expand_path(path || default_fn(extension), config.save_path).tap { |p_path| FileUtils.mkdir_p(File.dirname(p_path)) }
|
||||
File.expand_path(path || default_fn(extension), config.save_path).tap do |p_path|
|
||||
FileUtils.mkdir_p(File.dirname(p_path))
|
||||
end
|
||||
end
|
||||
|
||||
def default_fn(extension)
|
||||
|
|
|
@ -50,17 +50,17 @@ Capybara::SpecHelper.spec '#has_css?' do
|
|||
it 'should be able to generate an error message if the scope is a sibling' do
|
||||
el = @session.find(:css, '#first')
|
||||
@session.within el.sibling(:css, '#second') do
|
||||
expect {
|
||||
expect do
|
||||
expect(@session).to have_css('a#not_on_page')
|
||||
}.to raise_error /there were no matches/
|
||||
end.to raise_error(/there were no matches/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should be able to generate an error message if the scope is a sibling from XPath' do
|
||||
el = @session.find(:css, '#first').find(:xpath, './following-sibling::*[1]') do
|
||||
expect {
|
||||
expect do
|
||||
expect(el).to have_css('a#not_on_page')
|
||||
}.to raise_error /there were no matches/
|
||||
end.to raise_error(/there were no matches/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue