rubocop driven style cleanup

This commit is contained in:
Thomas Walpole 2018-01-09 14:05:50 -08:00
parent 5233962c7c
commit 24eb7a0702
51 changed files with 602 additions and 1695 deletions

File diff suppressed because it is too large Load Diff

View File

@ -3,8 +3,8 @@ source 'https://rubygems.org'
gem 'bundler', '~> 1.1'
gemspec
gem 'xpath', :git => 'git://github.com/teamcapybara/xpath.git'
gem 'xpath', git: 'git://github.com/teamcapybara/xpath.git'
group :doc do
gem 'redcarpet', :platforms => :mri
gem 'redcarpet', platforms: :mri
end

View File

@ -20,11 +20,11 @@ RSpec::Core::RakeTask.new(:spec_rack) do |t|
t.pattern = './spec{,/*/**}/*{_spec.rb}'
end
task :spec => [:spec_marionette]
task spec: [:spec_marionette]
YARD::Rake::YardocTask.new do |t|
t.files = ['lib/**/*.rb']
t.options = %w(--markup=markdown)
t.options = %w[--markup=markdown]
end
Cucumber::Rake::Task.new(:cucumber) do |task|
@ -52,4 +52,4 @@ task :release do
'git push --tags'
end
task :default => %i[spec cucumber]
task default: %i[spec cucumber]

View File

@ -21,6 +21,5 @@ When(/^I use a matcher that fails$/) do
end
Then(/^the failing exception should be nice$/) do
expect(@error_message).to match %r(expected to find visible css \"h1#doesnotexist\")
expect(@error_message).to match %r{expected to find visible css \"h1#doesnotexist\"}
end

View File

@ -20,4 +20,3 @@ Capybara.javascript_driver = :javascript_test
Capybara.register_driver :named_test do |app|
Capybara::RackTest::Driver.new(app)
end

View File

@ -22,7 +22,6 @@ module Capybara
class WindowError < CapybaraError; end
class ReadOnlyElementError < CapybaraError; end
class << self
extend Forwardable
@ -359,7 +358,7 @@ module Capybara
# @param [String] html The raw html
# @return [Nokogiri::HTML::Document] HTML document
#
def HTML(html)
def HTML(html) # rubocop:disable Naming/MethodName
Nokogiri::HTML(html).tap do |document|
document.xpath('//textarea').each do |textarea|
textarea['_capybara_raw_value'] = textarea.content.sub(/\A\n/, '')
@ -377,6 +376,7 @@ module Capybara
end
private
def config
@config ||= Capybara::Config.new
end
@ -439,7 +439,7 @@ 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))
Rack::Handler::WEBrick.run(app, { Host: host, Port: port, AccessLog: [], Logger: WEBrick::Log.new(nil, 0) }.merge(options))
end
Capybara.register_server :puma do |app, port, host, **options|
@ -476,11 +476,11 @@ Capybara.register_driver :selenium do |app|
end
Capybara.register_driver :selenium_chrome do |app|
Capybara::Selenium::Driver.new(app, :browser => :chrome)
Capybara::Selenium::Driver.new(app, browser: :chrome)
end
Capybara.register_driver :selenium_chrome_headless do |app|
browser_options = ::Selenium::WebDriver::Chrome::Options.new()
browser_options = ::Selenium::WebDriver::Chrome::Options.new
browser_options.args << '--headless'
browser_options.args << '--disable-gpu'
Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)

View File

@ -22,9 +22,7 @@ module Capybara
@session_options = Capybara::SessionConfig.new
end
def reuse_server=(bool)
@reuse_server = bool
end
attr_writer :reuse_server
def threadsafe=(bool)
warn "Capybara.threadsafe == true is a BETA feature and may change in future minor versions" if bool
@ -60,7 +58,7 @@ module Capybara
def server=(name)
name, options = *name if name.is_a? Array
@server = if options
Proc.new { |app, port, host| Capybara.servers[name.to_sym].call(app,port,host,options) }
proc { |app, port, host| Capybara.servers[name.to_sym].call(app, port, host, options) }
else
Capybara.servers[name.to_sym]
end

View File

@ -22,8 +22,6 @@ end
Before do |scenario|
scenario.source_tag_names.each do |tag|
driver_name = tag.sub(/^@/, '').to_sym
if Capybara.drivers.has_key?(driver_name)
Capybara.current_driver = driver_name
end
Capybara.current_driver = driver_name if Capybara.drivers.key?(driver_name)
end
end

View File

@ -103,7 +103,6 @@ class Capybara::Driver::Base
raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#no_such_window_error'
end
##
#
# Execute the block, and then accept the modal opened.

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true
module Capybara
# @api private
module Helpers
extend self

View File

@ -42,9 +42,8 @@ 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|
self.class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
%w[assert_text assert_no_text assert_title assert_no_title assert_current_path assert_no_current_path].each do |assertion_name|
class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
def #{assertion_name} *args
self.assertions +=1
subject, args = determine_subject(args)
@ -82,10 +81,10 @@ module Capybara
# @!method assert_xpath
# see {Capybara::Node::Matchers#assert_not_matches_selector}
%w(assert_selector assert_no_selector
%w[assert_selector assert_no_selector
assert_all_of_selectors assert_none_of_selectors
assert_matches_selector assert_not_matches_selector).each do |assertion_name|
self.class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
assert_matches_selector assert_not_matches_selector].each do |assertion_name|
class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
def #{assertion_name} *args, &optional_filter_block
self.assertions +=1
subject, args = determine_subject(args)
@ -99,7 +98,7 @@ module Capybara
alias_method :refute_selector, :assert_no_selector
alias_method :refute_matches_selector, :assert_not_matches_selector
%w(xpath css link button field select table).each do |selector_type|
%w[xpath css link button field select table].each do |selector_type|
define_method "assert_#{selector_type}" do |*args, &optional_filter_block|
subject, args = determine_subject(args)
locator, options = extract_locator(args)
@ -114,7 +113,7 @@ module Capybara
alias_method "refute_#{selector_type}", "assert_no_#{selector_type}"
end
%w(checked unchecked).each do |field_type|
%w[checked unchecked].each do |field_type|
define_method "assert_#{field_type}_field" do |*args, &optional_filter_block|
subject, args = determine_subject(args)
locator, options = extract_locator(args)
@ -129,7 +128,7 @@ module Capybara
alias_method "refute_#{field_type}_field", "assert_no_#{field_type}_field"
end
%w(xpath css).each do |selector_type|
%w[xpath css].each do |selector_type|
define_method "assert_matches_#{selector_type}" do |*args, &optional_filter_block|
subject, args = determine_subject(args)
assert_matches_selector(subject, selector_type.to_sym, *args, &optional_filter_block)

View File

@ -3,21 +3,22 @@ require 'minitest/spec'
module Capybara
module Minitest
module Expectations
%w(text content title current_path).each do |assertion|
%w[text content title current_path].each do |assertion|
infect_an_assertion "assert_#{assertion}", "must_have_#{assertion}", :reverse
infect_an_assertion "refute_#{assertion}", "wont_have_#{assertion}", :reverse
end
(%w(selector xpath css link button field select table checked_field unchecked_field).flat_map do |assertion|
[["assert_#{assertion}", "must_have_#{assertion}"],
["refute_#{assertion}", "wont_have_#{assertion}"]]
end + [["assert_all_of_selectors", "must_have_all_of_selectors"],
["assert_none_of_selectors", "must_have_none_of_selectors"]] +
%w(selector xpath css).flat_map do |assertion|
[["assert_matches_#{assertion}", "must_match_#{assertion}"],
["refute_matches_#{assertion}", "wont_match_#{assertion}"]]
# rubocop:disable Style/MultilineBlockChain
(%w[selector xpath css link button field select table checked_field unchecked_field].flat_map do |assertion|
[%W[assert_#{assertion} must_have_#{assertion}],
%W[refute_#{assertion} wont_have_#{assertion}]]
end + [%w[assert_all_of_selectors must_have_all_of_selectors],
%w[assert_none_of_selectors must_have_none_of_selectors]] +
%w[selector xpath css].flat_map do |assertion|
[%W[assert_matches_#{assertion} must_match_#{assertion}],
%W[refute_matches_#{assertion} wont_match_#{assertion}]]
end).each do |(meth, new_name)|
self.class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
def #{new_name} *args, &block
::Minitest::Expectation.new(self, ::Minitest::Spec.current).#{new_name}(*args, &block)
end
@ -29,6 +30,7 @@ module Capybara
end
ASSERTION
end
# rubocop:enable Style/MultilineBlockChain
##
# Expectation that there is xpath
@ -159,7 +161,6 @@ module Capybara
#
# @!method wont_have_current_path
# see {Capybara::SessionMatchers#assert_no_current_path}
end
end
end

View File

@ -3,7 +3,6 @@
module Capybara
module Node
module Actions
##
#
# Finds a button or link and clicks it. See {Capybara::Node::Actions#click_button} and
@ -82,7 +81,7 @@ module Capybara
#
# @return [Capybara::Node::Element] The element filled_in
def fill_in(locator = nil, with:, fill_options: {}, **options)
options[:with] = options.delete(:currently_with) if options.has_key?(:currently_with)
options[:with] = options.delete(:currently_with) if options.key?(:currently_with)
find(:fillable_field, locator, options).set(with, fill_options)
end
@ -225,30 +224,30 @@ module Capybara
# @option options [true, Hash] make_visible A Hash of CSS styles to change before attempting to attach the file, if `true` { opacity: 1, display: 'block', visibility: 'visible' } is used (may not be supported by all drivers)
#
# @return [Capybara::Node::Element] The file field element
def attach_file(locator=nil, path, make_visible: nil, **options)
def attach_file(locator = nil, path, make_visible: nil, **options) # rubocop:disable Style/OptionalArguments
Array(path).each do |p|
raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s)
end
# Allow user to update the CSS style of the file input since they are so often hidden on a page
if make_visible
make_visible = { opacity: 1, display: 'block', visibility: 'visible' } if make_visible == true
ff = find(:file_field, locator, options.merge({visible: :all}))
ff = find(:file_field, locator, options.merge(visible: :all))
_update_style(ff, make_visible)
if ff.visible?
raise ExpectationNotMet, "The style changes in :make_visible did not make the file input visible" unless ff.visible?
begin
ff.set(path)
ensure
_reset_style(ff)
end
else
raise ExpectationNotMet, "The style changes in :make_visible did not make the file input visible"
end
else
find(:file_field, locator, options).set(path)
end
end
private
def _update_style(element, style)
script = <<-JS
var el = arguments[0];
@ -277,12 +276,12 @@ module Capybara
JS
begin
session.execute_script(script, element)
rescue
rescue # swallow extra errors
end
end
def _check_with_label(selector, checked, locator, allow_label_click: session_options.automatic_label_click, **options)
synchronize(Capybara::Queries::BaseQuery::wait(options, session_options.default_max_wait_time)) do
synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do
begin
el = find(selector, locator, options)
el.set(checked)
@ -291,14 +290,13 @@ module Capybara
begin
el ||= find(selector, locator, options.merge(visible: :all))
label = find(:label, for: el, visible: true)
label.click unless (el.checked? == checked)
rescue
label.click unless el.checked? == checked
rescue # swallow extra errors - raise original
raise e
end
end
end
end
end
end
end

View File

@ -2,7 +2,6 @@
module Capybara
module Node
##
#
# A {Capybara::Node::Base} represents either an element on a page through the subclass

View File

@ -2,7 +2,6 @@
module Capybara
module Node
##
#
# A {Capybara::Document} represents an HTML document. Any operation

View File

@ -64,7 +64,6 @@ module Capybara
end
return true
end
end
end
end

View File

@ -2,7 +2,6 @@
module Capybara
module Node
##
#
# A {Capybara::Node::Element} represents a single element on the page. It is possible
@ -23,7 +22,6 @@ module Capybara
# @see Capybara::Node
#
class Element < Base
def initialize(session, base, query_scope, query)
super(session, base)
@query_scope = query_scope
@ -397,18 +395,15 @@ module Capybara
rescue NotSupportedByDriverError
%(#<Capybara::Node::Element tag="#{base.tag_name}">)
rescue => e
if session.driver.invalid_element_errors.any? { |et| e.is_a?(et)}
raise unless session.driver.invalid_element_errors.any? { |et| e.is_a?(et) }
%(Obsolete #<Capybara::Node::Element>)
else
raise
end
end
private
def verify_click_options_support(method)
if base.method(method).arity.zero?
raise ArgumentError, "The current driver does not support #{method} options"
end
raise ArgumentError, "The current driver does not support #{method} options" if base.method(method).arity.zero?
end
end
end

View File

@ -3,7 +3,6 @@
module Capybara
module Node
module Finders
##
#
# Find an {Capybara::Node::Element} based on the given arguments. +find+ will raise an error if the element
@ -298,7 +297,7 @@ module Capybara
def synced_resolve(query)
synchronize(query.wait) do
if (query.match == :smart or query.match == :prefer_exact)
if query.match == :smart or query.match == :prefer_exact
result = query.resolve_for(self, true)
result = query.resolve_for(self, false) if result.empty? && query.supports_exact? && !query.exact?
else
@ -306,11 +305,11 @@ module Capybara
end
if query.match == :one or query.match == :smart and result.size > 1
raise Capybara::Ambiguous.new("Ambiguous match, found #{result.size} elements matching #{query.description}")
end
if result.empty?
raise Capybara::ElementNotFound.new("Unable to find #{query.description}")
raise Capybara::Ambiguous, "Ambiguous match, found #{result.size} elements matching #{query.description}"
end
raise Capybara::ElementNotFound, "Unable to find #{query.description}" if result.empty?
result.first
end.tap(&:allow_reload!)
end

View File

@ -3,7 +3,6 @@
module Capybara
module Node
module Matchers
##
#
# Checks if a given selector is on the page or a descendant of the current node.
@ -114,7 +113,7 @@ module Capybara
# @overload assert_all_of_selectors([kind = Capybara.default_selector], *locators, options = {})
#
def assert_all_of_selectors(*args, wait: session_options.default_max_wait_time, **options, &optional_filter_block)
selector = if args.first.is_a?(Symbol) then args.shift else session_options.default_selector end
selector = args.first.is_a?(Symbol) ? args.shift : session_options.default_selector
synchronize(wait) do
args.each do |locator|
assert_selector(selector, locator, options, &optional_filter_block)
@ -138,7 +137,7 @@ module Capybara
# @overload assert_none_of_selectors([kind = Capybara.default_selector], *locators, options = {})
#
def assert_none_of_selectors(*args, wait: session_options.default_max_wait_time, **options, &optional_filter_block)
selector = if args.first.is_a?(Symbol) then args.shift else session_options.default_selector end
selector = args.first.is_a?(Symbol) ? args.shift : session_options.default_selector
synchronize(wait) do
args.each do |locator|
assert_no_selector(selector, locator, options, &optional_filter_block)
@ -568,7 +567,6 @@ module Capybara
not_matches_selector?(:css, css, options, &optional_filter_block)
end
##
# Asserts that the page or current node has the given text content,
# ignoring any HTML tags.
@ -658,7 +656,7 @@ module Capybara
alias_method :has_no_content?, :has_no_text?
def ==(other)
self.eql?(other) || (other.respond_to?(:base) && base == other.base)
eql?(other) || (other.respond_to?(:base) && base == other.base)
end
private
@ -677,7 +675,7 @@ module Capybara
_set_query_session_options(query_args)
query = Capybara::Queries::MatchQuery.new(*query_args, &optional_filter_block)
synchronize(query.wait) do
result = query.resolve_for(self.query_scope)
result = query.resolve_for(query_scope)
yield result
end
return true

View File

@ -2,7 +2,6 @@
module Capybara
module Node
##
#
# A {Capybara::Node::Simple} is a simpler version of {Capybara::Node::Base} which
@ -85,7 +84,7 @@ module Capybara
option = native.xpath(".//option[@selected='selected']").first || native.xpath(".//option").first
option[:value] || option.content if option
end
elsif tag_name == 'input' && %w(radio checkbox).include?(native[:type])
elsif tag_name == 'input' && %w[radio checkbox].include?(native[:type])
native[:value] || 'on'
else
native[:value]
@ -106,8 +105,8 @@ module Capybara
if check_ancestors
!native.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))
# 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))
end
end

View File

@ -31,7 +31,7 @@ module Capybara
# Returns false if query does not have any count options specified.
#
def expects_none?
if COUNT_KEYS.any? { |k| options.has_key? k }
if COUNT_KEYS.any? { |k| options.key? k }
matches_count?(0)
else
false
@ -51,7 +51,7 @@ module Capybara
return (Integer(options[:count]) == count) if options[:count]
return false if options[:maximum] && (Integer(options[:maximum]) < count)
return false if options[:minimum] && (Integer(options[:minimum]) > count)
return false if options[:between] && !(options[:between] === count)
return false if options[:between] && !options[:between].include?(count)
return true
end
@ -70,7 +70,7 @@ module Capybara
private
def count_message
message = String.new()
message = "".dup
if options[:count]
message << " #{options[:count]} #{Capybara::Helpers.declension('time', 'times', options[:count])}"
elsif options[:between]
@ -85,7 +85,8 @@ module Capybara
def assert_valid_keys
invalid_keys = @options.keys - valid_keys
unless invalid_keys.empty?
return if invalid_keys.empty?
invalid_names = invalid_keys.map(&:inspect).join(", ")
valid_names = valid_keys.map(&:inspect).join(", ")
raise ArgumentError, "invalid keys #{invalid_names}, should be one of #{valid_names}"
@ -93,4 +94,3 @@ module Capybara
end
end
end
end

View File

@ -50,7 +50,6 @@ module Capybara
def valid_keys
%i[wait url ignore_query]
end
end
end
end

View File

@ -2,7 +2,7 @@ module Capybara
module Queries
class MatchQuery < Capybara::Queries::SelectorQuery
def visible
if options.has_key?(:visible)
if options.key?(:visible)
super
else
:all

View File

@ -38,7 +38,7 @@ module Capybara
def label; selector.label or selector.name; end
def description
@description = String.new()
@description = "".dup
@description << "visible " if visible == :visible
@description << "non-visible " if visible == :hidden
@description << "#{label} #{locator.inspect}"
@ -53,8 +53,8 @@ module Capybara
end
def matches_filters?(node)
return false unless matches_text_filter(node, options[:text]) if options[:text]
return false unless matches_exact_text_filter(node, exact_text) if exact_text.is_a?(String)
return false if options[:text] && !matches_text_filter(node, options[:text])
return false if exact_text.is_a?(String) && !matches_exact_text_filter(node, exact_text)
case visible
when :visible then return false unless node.visible?
@ -62,7 +62,7 @@ module Capybara
end
res = node_filters.all? do |name, filter|
if options.has_key?(name)
if options.key?(name)
filter.matches?(node, options[name])
elsif filter.default?
filter.matches?(node, filter.default)
@ -71,11 +71,13 @@ module Capybara
end
end
if @filter_block
res &&= if node.respond_to?(:session)
node.session.using_wait_time(0) { @filter_block.call(node) }
else
@filter_block.call(node)
end unless @filter_block.nil?
end
end
res
rescue *(node.respond_to?(:session) ? node.session.driver.invalid_element_errors : [])
@ -91,7 +93,7 @@ module Capybara
end
def exact?
return false if !supports_exact?
return false unless supports_exact?
options.fetch(:exact, session_options.exact)
end
@ -100,13 +102,9 @@ module Capybara
end
def xpath(exact = nil)
exact = self.exact? if exact.nil?
exact = exact? if exact.nil?
expr = apply_expression_filters(@expression)
expr = if expr.respond_to?(:to_xpath) and exact
expr.to_xpath(:exact)
else
expr.to_s
end
expr = exact ? expr.to_xpath(:exact) : expr.to_s if expr.respond_to?(:to_xpath)
filtered_xpath(expr)
end
@ -119,9 +117,9 @@ module Capybara
@resolved_node = node
node.synchronize do
children = if selector.format == :css
node.find_css(self.css)
node.find_css(css)
else
node.find_xpath(self.xpath(exact))
node.find_xpath(xpath(exact))
end.map do |child|
if node.is_a?(Capybara::Node::Base)
Capybara::Node::Element.new(node.session, child, node, self)
@ -145,7 +143,7 @@ module Capybara
end
def node_filters
if options.has_key?(:filter_set)
if options.key?(:filter_set)
::Capybara::Selector::FilterSet.all[options[:filter_set]].node_filters
else
@selector.node_filters
@ -154,7 +152,7 @@ module Capybara
def expression_filters
filters = @selector.expression_filters
filters.merge ::Capybara::Selector::FilterSet.all[options[:filter_set]].expression_filters if options.has_key?(:filter_set)
filters.merge ::Capybara::Selector::FilterSet.all[options[:filter_set]].expression_filters if options.key?(:filter_set)
filters
end
@ -170,10 +168,10 @@ module Capybara
end
def filtered_xpath(expr)
if options.has_key?(:id) || options.has_key?(:class)
if options.key?(:id) || options.key?(:class)
expr = "(#{expr})"
expr = "#{expr}[#{XPath.attr(:id) == options[:id]}]" if options.has_key?(:id) && !custom_keys.include?(:id)
if options.has_key?(:class) && !custom_keys.include?(:class)
expr = "#{expr}[#{XPath.attr(:id) == options[:id]}]" if options.key?(:id) && !custom_keys.include?(:id)
if options.key?(:class) && !custom_keys.include?(:class)
class_xpath = Array(options[:class]).map do |klass|
XPath.attr(:class).contains_word(klass)
end.reduce(:&)
@ -184,11 +182,11 @@ module Capybara
end
def filtered_css(expr)
if options.has_key?(:id) || options.has_key?(:class)
if options.key?(:id) || options.key?(:class)
css_selectors = expr.split(',').map(&:rstrip)
expr = css_selectors.map do |sel|
sel += "##{Capybara::Selector::CSS.escape(options[:id])}" if options.has_key?(:id) && !custom_keys.include?(:id)
sel += Array(options[:class]).map { |k| ".#{Capybara::Selector::CSS.escape(k)}"}.join if options.has_key?(:class) && !custom_keys.include?(:class)
sel += "##{Capybara::Selector::CSS.escape(options[:id])}" if options.key?(:id) && !custom_keys.include?(:id)
sel += Array(options[:class]).map { |k| ".#{Capybara::Selector::CSS.escape(k)}" }.join if options.key?(:class) && !custom_keys.include?(:class)
sel
end.join(", ")
end
@ -197,7 +195,7 @@ module Capybara
def apply_expression_filters(expr)
expression_filters.inject(expr) do |memo, (name, ef)|
if options.has_key?(name)
if options.key?(name)
ef.apply_filter(memo, options[name])
elsif ef.default?
ef.apply_filter(memo, ef.default)
@ -208,10 +206,9 @@ module Capybara
end
def warn_exact_usage
if options.has_key?(:exact) && !supports_exact?
return unless options.key?(:exact) && !supports_exact?
warn "The :exact option only has an effect on queries using the XPath#is method. Using it with the query \"#{expression}\" has no effect."
end
end
def exact_text
options.fetch(:exact_text, session_options.exact_text)

View File

@ -4,9 +4,9 @@ module Capybara
# @api private
module Queries
class TextQuery < BaseQuery
def initialize(type=nil, expected_text, session_options:, **options)
def initialize(type = nil, expected_text, session_options:, **options) # rubocop:disable Style/OptionalArguments
@type = type
@type = Capybara.ignore_hidden_elements or Capybara.visible_text_only ? :visible : :all if @type.nil?
@type = Capybara.ignore_hidden_elements || Capybara.visible_text_only ? :visible : :all if @type.nil?
@expected_text = expected_text
@options = options
super(@options)
@ -47,7 +47,7 @@ module Capybara
end
def build_message(report_on_invisible)
message = String.new()
message = "".dup
unless (COUNT_KEYS & @options.keys).empty?
message << " but found #{@count} #{Capybara::Helpers.declension('time', 'times', @count)}"
end
@ -70,8 +70,7 @@ module Capybara
if invisible_count != @count
details_message << "it was found #{invisible_count} #{Capybara::Helpers.declension("time", "times", invisible_count)} including non-visible text"
end
rescue
# An error getting the non-visible text (if element goes out of scope) should not affect the response
rescue # An error getting the non-visible text (if element goes out of scope) should not affect the response
end
end

View File

@ -29,24 +29,25 @@ class Capybara::RackTest::Browser
end
def submit(method, path, attributes)
path = request_path if not path or path.empty?
process_and_follow_redirects(method, path, attributes, {'HTTP_REFERER' => current_url})
path = request_path if path.nil? || path.empty?
process_and_follow_redirects(method, path, attributes, 'HTTP_REFERER' => current_url)
end
def follow(method, path, **attributes)
return if path.gsub(/^#{Regexp.escape(request_path)}/, '').start_with?('#') || path.downcase.start_with?('javascript:')
process_and_follow_redirects(method, path, attributes, {'HTTP_REFERER' => current_url})
process_and_follow_redirects(method, path, attributes, 'HTTP_REFERER' => current_url)
end
def process_and_follow_redirects(method, path, attributes = {}, env = {})
process(method, path, attributes, env)
if driver.follow_redirects?
return unless driver.follow_redirects?
driver.redirect_limit.times do
process(:get, last_response["Location"], {}, env) if last_response.redirect?
end
raise Capybara::InfiniteRedirectError, "redirected more than #{driver.redirect_limit} times, check for infinite redirects." if last_response.redirect?
end
end
def process(method, path, attributes = {}, env = {})
new_uri = URI.parse(path)
@ -56,7 +57,7 @@ class Capybara::RackTest::Browser
else
new_uri.path = request_path if path.start_with?("?")
new_uri.path = "/" if new_uri.path.empty?
new_uri.path = request_path.sub(%r(/[^/]*$), '/') + new_uri.path unless new_uri.path.start_with?('/')
new_uri.path = request_path.sub(%r{/[^/]*$}, '/') + new_uri.path unless new_uri.path.start_with?('/')
end
new_uri.scheme ||= @current_scheme
new_uri.host ||= @current_host

View File

@ -3,10 +3,11 @@
class Capybara::RackTest::CSSHandlers < BasicObject
include ::Kernel
def disabled list
def disabled(list)
list.find_all { |node| node.has_attribute? 'disabled' }
end
def enabled list
def enabled(list)
list.find_all { |node| !node.has_attribute? 'disabled' }
end
end

View File

@ -82,12 +82,12 @@ private
end
def add_input_param(field, params)
if %w(radio checkbox).include? field['type']
if %w[radio checkbox].include? field['type']
if field['checked']
node=Capybara::RackTest::Node.new(self.driver, field)
node = Capybara::RackTest::Node.new(driver, field)
merge_param!(params, field['name'].to_s, node.value.to_s)
end
elsif %w(submit image).include? field['type']
elsif %w[submit image].include? field['type']
# TO DO identify the click button here (in document order, rather
# than leaving until the end of the params)
elsif field['type'] == 'file'

View File

@ -20,8 +20,8 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
def set(value)
return if disabled? || readonly?
if (Array === value) && !multiple?
raise TypeError.new "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
if value.is_a?(Array) && !multiple?
raise TypeError, "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
end
if radio?
@ -55,13 +55,13 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
method = self["data-method"] if driver.options[:respect_data_method]
method ||= :get
driver.follow(method, self[:href].to_s)
elsif (tag_name == 'input' and %w(submit image).include?(type)) or
((tag_name == 'button') and type.nil? or type == "submit")
elsif (tag_name == 'input' and %w[submit image].include?(type)) or
(tag_name == 'button' and [nil, "submit"].include?(type))
associated_form = form
Capybara::RackTest::Form.new(driver, associated_form).submit(self) if associated_form
elsif (tag_name == 'input' and %w(checkbox radio).include?(type))
elsif tag_name == 'input' and %w[checkbox radio].include?(type)
set(!checked?)
elsif (tag_name == 'label')
elsif tag_name == 'label'
labelled_control = if native[:for]
find_xpath("//input[@id='#{native[:for]}']").first
else
@ -91,7 +91,7 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
end
def disabled?
if %w(option optgroup).include? tag_name
if %w[option optgroup].include? tag_name
string_node.disabled? || find_xpath("parent::*[self::optgroup or self::select]")[0].disabled?
else
string_node.disabled? || !find_xpath("parent::fieldset[@disabled] | ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]").empty?
@ -153,13 +153,13 @@ private
end
end
def set_radio(_value)
def set_radio(_value) # rubocop:disable Naming/AccessorMethodName
other_radios_xpath = XPath.generate { |x| x.anywhere(:input)[x.attr(:name) == self[:name]] }.to_s
driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute("checked") }
native['checked'] = 'checked'
end
def set_checkbox(value)
def set_checkbox(value) # rubocop:disable Naming/AccessorMethodName
if value && !native['checked']
native['checked'] = 'checked'
elsif !value && native['checked']
@ -167,13 +167,13 @@ private
end
end
def set_input(value)
def set_input(value) # rubocop:disable Naming/AccessorMethodName
if text_or_password? && attribute_is_not_blank?(:maxlength)
# Browser behavior for maxlength="0" is inconsistent, so we stick with
# Firefox, allowing no input
value = value.to_s[0...self[:maxlength].to_i]
end
if Array === value #Assert multiple attribute is present
if value.is_a?(Array) # Assert multiple attribute is present
value.each do |v|
new_native = native.clone
new_native.remove_attribute('value')

View File

@ -3,7 +3,6 @@
require 'forwardable'
module Capybara
##
# A {Capybara::Result} represents a collection of {Capybara::Node::Element} on the page. It is possible to interact with this
# collection similar to an Array because it implements Enumerable and offers the following Array methods through delegation:
@ -100,7 +99,7 @@ module Capybara
break if @result_cache.size > max
@result_cache << @results_enum.next
end
return 0 if (@query.options[:between] === @result_cache.size)
return 0 if @query.options[:between].include?(@result_cache.size)
return -1 if @result_cache.size < min
return 1
end

View File

@ -7,9 +7,9 @@ require 'capybara/rspec/features'
require 'capybara/rspec/matcher_proxies'
RSpec.configure do |config|
config.include Capybara::DSL, :type => :feature
config.include Capybara::RSpecMatchers, :type => :feature
config.include Capybara::RSpecMatchers, :type => :view
config.include Capybara::DSL, type: :feature
config.include Capybara::RSpecMatchers, type: :feature
config.include Capybara::RSpecMatchers, type: :view
# The before and after blocks must run instantaneously, because Capybara
# might not actually be used in all examples where it's included.
@ -28,4 +28,3 @@ RSpec.configure do |config|
end
end
end

View File

@ -15,7 +15,6 @@ module Capybara
Capybara::RSpecMatchers::Compound::Or.new(self, matcher)
end
class CapybaraEvaluator
def initialize(actual, matcher1, matcher2)
@actual = actual
@ -34,16 +33,15 @@ module Capybara
end
class And < ::RSpec::Matchers::BuiltIn::Compound::And
private
def match(_expected, actual)
@evaluator = CapybaraEvaluator.new(actual, matcher1, matcher2)
@evaluator = CapybaraEvaluator.new(actual, matcher_1, matcher_2)
syncer = sync_element(actual)
begin
syncer.synchronize do
@evaluator.reset
raise ::Capybara::ElementNotFound unless [matcher1_matches?, matcher2_matches?].all?
raise ::Capybara::ElementNotFound unless [matcher_1_matches?, matcher_2_matches?].all?
true
end
rescue
@ -63,16 +61,15 @@ module Capybara
end
class Or < ::RSpec::Matchers::BuiltIn::Compound::Or
private
def match(_expected, actual)
@evaluator = CapybaraEvaluator.new(actual, matcher1, matcher2)
@evaluator = CapybaraEvaluator.new(actual, matcher_1, matcher_2)
syncer = sync_element(actual)
begin
syncer.synchronize do
@evaluator.reset
raise ::Capybara::ElementNotFound unless [matcher1_matches?, matcher2_matches?].any?
raise ::Capybara::ElementNotFound unless [matcher_1_matches?, matcher_2_matches?].any?
true
end
rescue

View File

@ -2,16 +2,16 @@
require 'capybara/selector/selector'
Capybara::Selector::FilterSet.add(:_field) do
filter(:checked, :boolean) { |node, value| not(value ^ node.checked?) }
filter(:checked, :boolean) { |node, value| !(value ^ node.checked?) }
filter(:unchecked, :boolean) { |node, value| (value ^ node.checked?) }
filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| !(value ^ node.disabled?) }
filter(:multiple, :boolean) { |node, value| !(value ^ node.multiple?) }
expression_filter(:name) { |xpath, val| xpath[XPath.attr(:name) == val] }
expression_filter(:placeholder) { |xpath, val| xpath[XPath.attr(:placeholder) == val] }
describe do |checked: nil, unchecked: nil, disabled: nil, multiple: nil, **_options|
desc, states = String.new, []
desc, states = "".dup, []
states << 'checked' if checked || (unchecked == false)
states << 'not checked' if unchecked || (checked == false)
states << 'disabled' if disabled == true
@ -80,7 +80,7 @@ Capybara.add_selector(:field) do
expression_filter(:type) do |expr, type|
type = type.to_s
if ['textarea', 'select'].include?(type)
if %w[textarea select].include?(type)
expr.self(type.to_sym)
else
expr[XPath.attr(:type) == type]
@ -89,15 +89,15 @@ Capybara.add_selector(:field) do
filter_set(:_field) # checked/unchecked/disabled/multiple/name/placeholder
filter(:readonly, :boolean) { |node, value| not(value ^ node.readonly?) }
filter(:readonly, :boolean) { |node, value| !(value ^ node.readonly?) }
filter(:with) do |node, with|
with.is_a?(Regexp) ? node.value =~ with : node.value == with.to_s
end
describe do |type: nil, **options|
desc = String.new
(expression_filters.keys - [:type]).each { |ef| desc << " with #{ef} #{options[ef]}" if options.has_key?(ef) }
desc = "".dup
(expression_filters.keys - [:type]).each { |ef| desc << " with #{ef} #{options[ef]}" if options.key?(ef) }
desc << " of type #{type.inspect}" if type
desc << " with value #{options[:with].to_s.inspect}" if options.has_key?(:with)
desc << " with value #{options[:with].to_s.inspect}" if options.key?(:with)
desc
end
end
@ -167,7 +167,7 @@ Capybara.add_selector(:link) do
end
describe do |**options|
desc = String.new()
desc = "".dup
desc << " with href #{options[:href].inspect}" if options[:href]
desc << " with no href attribute" if options.fetch(:href, true).nil?
end
@ -211,10 +211,10 @@ Capybara.add_selector(:button) do
res_xpath
end
filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| !(value ^ node.disabled?) }
describe do |disabled: nil, **options|
desc = String.new
desc = "".dup
desc << " that is disabled" if disabled == true
desc << describe_all_expression_filters(options)
desc
@ -231,7 +231,7 @@ Capybara.add_selector(:link_or_button) do
self.class.all.values_at(:link, :button).map { |selector| selector.xpath.call(locator, options) }.reduce(:union)
end
filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| node.tag_name == "a" or not(value ^ node.disabled?) }
filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| node.tag_name == "a" or !(value ^ node.disabled?) }
describe { |disabled: nil, **_options| " that is disabled" if disabled == true }
end
@ -274,9 +274,9 @@ Capybara.add_selector(:fillable_field) do
end
describe do |options|
desc = String.new
desc = "".dup
desc << describe_all_expression_filters(options)
desc << " with value #{options[:with].to_s.inspect}" if options.has_key?(:with)
desc << " with value #{options[:with].to_s.inspect}" if options.key?(:with)
desc
end
end
@ -307,7 +307,7 @@ Capybara.add_selector(:radio_button) do
filter(:option) { |node, value| node.value == value.to_s }
describe do |option: nil, **options|
desc = String.new
desc = "".dup
desc << " with value #{option.inspect}" if option
desc << describe_all_expression_filters(options)
desc
@ -328,7 +328,6 @@ end
# @filter [String] :option Match the value
#
Capybara.add_selector(:checkbox) do
xpath do |locator, **options|
xpath = XPath.descendant(:input)[XPath.attr(:type) == 'checkbox']
locate_field(xpath, locator, options)
@ -339,7 +338,7 @@ Capybara.add_selector(:checkbox) do
filter(:option) { |node, value| node.value == value.to_s }
describe do |option: nil, **options|
desc = String.new
desc = "".dup
desc << " with value #{option.inspect}" if option
desc << describe_all_expression_filters(options)
desc
@ -374,7 +373,7 @@ Capybara.add_selector(:select) do
filter(:options) do |node, options|
actual = if node.visible?
node.all(:xpath, './/option', wait: false).map { |option| option.text }
node.all(:xpath, './/option', wait: false).map(&:text)
else
node.all(:xpath, './/option', visible: false, wait: false).map { |option| option.text(:all) }
end
@ -383,9 +382,7 @@ Capybara.add_selector(:select) do
filter(:with_options) do |node, options|
finder_settings = { minimum: 0 }
if !node.visible?
finder_settings[:visible] = false
end
finder_settings[:visible] = false unless node.visible?
options.all? { |option| node.first(:option, option, finder_settings) }
end
@ -400,7 +397,7 @@ Capybara.add_selector(:select) do
end
describe do |options: nil, with_options: nil, selected: nil, with_selected: nil, **opts|
desc = String.new
desc = "".dup
desc << " with options #{options.inspect}" if options
desc << " with at least options #{with_options.inspect}" if with_options
desc << " with #{selected.inspect} selected" if selected
@ -425,13 +422,13 @@ Capybara.add_selector(:option) do
xpath
end
filter(:disabled, :boolean) { |node, value| not(value ^ node.disabled?) }
filter(:selected, :boolean) { |node, value| not(value ^ node.selected?) }
filter(:disabled, :boolean) { |node, value| !(value ^ node.disabled?) }
filter(:selected, :boolean) { |node, value| !(value ^ node.selected?) }
describe do |**options|
desc = String.new
desc << " that is#{' not' unless options[:disabled]} disabled" if options.has_key?(:disabled)
desc << " that is#{' not' unless options[:selected]} selected" if options.has_key?(:selected)
desc = "".dup
desc << " that is#{' not' unless options[:disabled]} disabled" if options.key?(:disabled)
desc << " that is#{' not' unless options[:selected]} selected" if options.key?(:selected)
desc
end
end
@ -457,7 +454,7 @@ Capybara.add_selector(:file_field) do
filter_set(:_field, %i[disabled multiple name])
describe do |**options|
desc = String.new
desc = "".dup
desc << describe_all_expression_filters(options)
desc
end
@ -475,9 +472,9 @@ Capybara.add_selector(:label) do
xpath(:for) do |locator, options|
xpath = XPath.descendant(:label)
xpath = xpath[XPath.string.n.is(locator.to_s) | (XPath.attr(:id) == locator.to_s)] unless locator.nil?
if options.has_key?(:for) && !options[:for].is_a?(Capybara::Node::Element)
if options.key?(:for) && !options[:for].is_a?(Capybara::Node::Element)
with_attr = XPath.attr(:for).equals(options[:for].to_s)
labelable_elements = %i(button input keygen meter output progress select textarea)
labelable_elements = %i[button input keygen meter output progress select textarea]
wrapped = !XPath.attr(:for) &
XPath.descendant(*labelable_elements)[XPath.attr(:id) == options[:for].to_s]
xpath = xpath[with_attr | wrapped]
@ -499,7 +496,7 @@ Capybara.add_selector(:label) do
end
describe do |**options|
desc = String.new
desc = "".dup
desc << " for #{options[:for]}" if options[:for]
desc
end
@ -523,7 +520,7 @@ Capybara.add_selector(:table) do
end
describe do |caption: nil, **_options|
desc = String.new
desc = "".dup
desc << " with caption #{caption}" if caption
desc
end
@ -547,7 +544,7 @@ Capybara.add_selector(:frame) do
end
describe do |name: nil, **_options|
desc = String.new
desc = "".dup
desc << " with name #{name}" if name
desc
end

View File

@ -2,20 +2,16 @@ module Capybara
class Selector
class CSS
def self.escape(str)
out = String.new("")
out = "".dup
value = str.dup
out << value.slice!(0...1) if value =~ /^[-_]/
out << if value[0] =~ NMSTART
value.slice!(0...1)
else
escape_char(value.slice!(0...1))
end
out << (value[0] =~ NMSTART ? value.slice!(0...1) : escape_char(value.slice!(0...1)))
out << value.gsub(/[^a-zA-Z0-9_-]/) { |c| escape_char c }
out
end
def self.escape_char(c)
return "\\%06x" % c.ord() unless c =~ %r{[ -/:-~]}
return format("\\%06x", c.ord) unless c =~ %r{[ -/:-~]}
"\\#{c}"
end

View File

@ -28,7 +28,7 @@ module Capybara
def description(**options)
options_with_defaults = options.dup
filters.each do |name, filter|
options_with_defaults[name] = filter.default if filter.default? && !options_with_defaults.has_key?(name)
options_with_defaults[name] = filter.default if filter.default? && !options_with_defaults.key?(name)
end
@descriptions.map do |desc|
@ -49,7 +49,6 @@ module Capybara
end
class << self
def all
@filter_sets ||= {}
end

View File

@ -12,7 +12,7 @@ module Capybara
end
def default?
@options.has_key?(:default)
@options.key?(:default)
end
def default
@ -20,13 +20,13 @@ module Capybara
end
def skip?(value)
@options.has_key?(:skip_if) && value == @options[:skip_if]
@options.key?(:skip_if) && value == @options[:skip_if]
end
private
def valid_value?(value)
!@options.has_key?(:valid_values) || Array(@options[:valid_values]).include?(value)
!@options.key?(:valid_values) || Array(@options[:valid_values]).include?(value)
end
end
end

View File

@ -9,7 +9,7 @@ module Capybara
def apply_filter(expr, value)
return expr if skip?(value)
if !valid_value?(value)
unless valid_value?(value)
msg = "Invalid value #{value.inspect} passed to expression filter #{@name} - "
if default?
warn msg + "defaulting to #{default}"

View File

@ -9,7 +9,7 @@ module Capybara
def matches?(node, value)
return true if skip?(value)
if !valid_value?(value)
unless valid_value?(value)
msg = "Invalid value #{value.inspect} passed to filter #{@name} - "
if default?
warn msg + "defaulting to #{default}"

View File

@ -21,7 +21,6 @@ end
module Capybara
class Selector
attr_reader :name, :format
class << self
@ -202,7 +201,7 @@ module Capybara
f_set.descriptions.each { |desc| @filter_set.describe(&desc) }
end
def describe &block
def describe(&block)
@filter_set.describe(&block)
end
@ -235,14 +234,14 @@ module Capybara
end
def locate_field(xpath, locator, enable_aria_label: false, **_options)
locate_xpath = xpath #need to save original xpath for the label wrap
locate_xpath = xpath # Need to save original xpath for the label wrap
if locator
locator = locator.to_s
attr_matchers = [XPath.attr(:id).equals(locator),
XPath.attr(:name).equals(locator),
XPath.attr(:placeholder).equals(locator),
XPath.attr(:id).equals(XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for))].reduce(:|)
attr_matchers = attr_matchers | XPath.attr(:'aria-label').is(locator) if enable_aria_label
attr_matchers |= XPath.attr(:'aria-label').is(locator) if enable_aria_label
locate_xpath = locate_xpath[attr_matchers]
locate_xpath = locate_xpath.union(XPath.descendant(:label)[XPath.string.n.is(locator)].descendant(xpath))
@ -253,7 +252,7 @@ module Capybara
end
def describe_all_expression_filters(**opts)
expression_filters.map { |ef| " with #{ef} #{opts[ef]}" if opts.has_key?(ef) }.join
expression_filters.map { |ef| " with #{ef} #{opts[ef]}" if opts.key?(ef) }.join
end
def find_by_attr(attribute, value)

View File

@ -1,11 +1,11 @@
# frozen_string_literal: true
require "uri"
require "English"
class Capybara::Selenium::Driver < Capybara::Driver::Base
DEFAULT_OPTIONS = {
:browser => :firefox,
browser: :firefox,
clear_local_storage: false,
clear_session_storage: false
}.freeze
@ -17,7 +17,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
unless @browser
if firefox?
options[:desired_capabilities] ||= {}
options[:desired_capabilities].merge!({ unexpectedAlertBehaviour: "ignore" })
options[:desired_capabilities][:unexpectedAlertBehaviour] = "ignore"
end
@processed_options = options.reject { |key, _val| SPECIAL_OPTIONS.include?(key) }
@ -28,7 +28,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
main = Process.pid
at_exit do
# Store the exit status of the test run since it goes away after calling the at_exit proc...
@exit_status = $!.status if $!.is_a?(SystemExit)
@exit_status = $ERROR_INFO.status if $ERROR_INFO.is_a?(SystemExit)
quit if Process.pid == main
exit @exit_status if @exit_status # Force exit with stored status
end
@ -109,11 +109,12 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
def reset!
# Use instance variable directly so we avoid starting the browser just to reset the session
if @browser
return unless @browser
navigated = false
start_time = Capybara::Helpers.monotonic_time
begin
if !navigated
unless navigated
# Only trigger a navigation if we haven't done it already, otherwise it
# can trigger an endless series of unload modals
begin
@ -129,8 +130,8 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
navigated = true
# Ensure the page is empty and trigger an UnhandledAlertError for any modals that appear during unload
until find_xpath("/html/body/*").empty? do
raise Capybara::ExpectationNotMet.new('Timed out waiting for Selenium session reset') if (Capybara::Helpers.monotonic_time - start_time) >= 10
until find_xpath("/html/body/*").empty?
raise Capybara::ExpectationNotMet, 'Timed out waiting for Selenium session reset' if (Capybara::Helpers.monotonic_time - start_time) >= 10
sleep 0.05
end
rescue Selenium::WebDriver::Error::UnhandledAlertError, Selenium::WebDriver::Error::UnexpectedAlertOpenError
@ -147,7 +148,6 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
retry
end
end
end
def switch_to_frame(frame)
case frame
@ -269,7 +269,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
::Selenium::WebDriver::Error::ElementNotInteractableError,
::Selenium::WebDriver::Error::ElementClickInterceptedError,
::Selenium::WebDriver::Error::InvalidElementStateError,
::Selenium::WebDriver::Error::ElementNotSelectableError,
::Selenium::WebDriver::Error::ElementNotSelectableError
]
end
@ -303,7 +303,6 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
return false
end
private
# @api private
@ -393,7 +392,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
# rubocop:enable Metrics/MethodLength
def within_given_window(handle)
original_handle = self.current_window_handle
original_handle = current_window_handle
if handle == original_handle
yield
else
@ -418,7 +417,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
alert.text.match(regexp) ? alert : nil
end
rescue Selenium::WebDriver::Error::TimeOutError
raise Capybara::ModalNotFound.new("Unable to find modal dialog#{" with #{text}" if text}")
raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{text}" if text}"
end
end
@ -438,7 +437,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
if alert_text.match(regexp)
alert_text
else
raise Capybara::ModalNotFound.new("Unable to find modal dialog#{" with #{text}" if text}")
raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{text}" if text}"
end
elsif called.nil?
# page changed so modal_handler data has gone away
@ -449,7 +448,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
end
end
rescue Selenium::WebDriver::Error::TimeOutError
raise Capybara::ModalNotFound.new("Unable to find modal dialog#{" with #{options[:text]}" if options[:text]}")
raise Capybara::ModalNotFound, "Unable to find modal dialog#{" with #{options[:text]}" if options[:text]}"
end
end
@ -475,13 +474,12 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
end
def load_selenium
begin
require 'selenium-webdriver'
# Fix for selenium-webdriver 3.4.0 which misnamed these
if !defined?(::Selenium::WebDriver::Error::ElementNotInteractableError)
unless defined?(::Selenium::WebDriver::Error::ElementNotInteractableError)
::Selenium::WebDriver::Error.const_set('ElementNotInteractableError', Class.new(::Selenium::WebDriver::Error::WebDriverError))
end
if !defined?(::Selenium::WebDriver::Error::ElementClickInterceptedError)
unless defined?(::Selenium::WebDriver::Error::ElementClickInterceptedError)
::Selenium::WebDriver::Error.const_set('ElementClickInterceptedError', Class.new(::Selenium::WebDriver::Error::WebDriverError))
end
rescue LoadError => e
@ -492,4 +490,3 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
end
end
end
end

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true
class Capybara::Selenium::Node < Capybara::Driver::Node
def visible_text
# Selenium doesn't normalize Unicode whitespace.
Capybara::Helpers.normalize_whitespace(native.text)
@ -41,8 +40,8 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
tag_name = self.tag_name
type = self[:type]
if (Array === value) && !multiple?
raise ArgumentError.new "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
if value.is_a?(Array) && !multiple?
raise ArgumentError, "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
end
case tag_name
@ -60,9 +59,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
when 'textarea'
set_text(value, options)
else
if content_editable?
set_content_editable(value)
end
set_content_editable(value) if content_editable?
end
end
@ -71,7 +68,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
end
def unselect_option
raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box." if !select_node.multiple?
raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box." unless select_node.multiple?
native.click if selected?
end
@ -94,7 +91,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
e.message =~ /Other element would receive the click/
begin
driver.execute_script("arguments[0].scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'})", self)
rescue
rescue # Swallow error if scrollIntoView with options isn't supported
end
end
raise e
@ -158,7 +155,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
def disabled?
# workaround for selenium-webdriver/geckodriver reporting elements as enabled when they are nested in disabling elements
if driver.marionette?
if %w(option optgroup).include? tag_name
if %w[option optgroup].include? tag_name
!native.enabled? || find_xpath("parent::*[self::optgroup or self::select]")[0].disabled?
else
!native.enabled? || !find_xpath("parent::fieldset[@disabled] | ancestor::*[not(self::legend) or preceding-sibling::legend][parent::fieldset[@disabled]]").empty?
@ -219,6 +216,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
end
private
# a reference to the select node if this is an option node
def select_node
find_xpath('./ancestor::select[1]').first
@ -258,7 +256,7 @@ private
yield
end
def set_file(value)
def set_file(value) # rubocop:disable Naming/AccessorMethodName
path_names = value.to_s.empty? ? [] : value
if driver.chrome?
native.send_keys(Array(path_names).join("\n"))
@ -267,8 +265,8 @@ private
end
end
def set_content_editable(value)
#ensure we are focused on the element
def set_content_editable(value) # rubocop:disable Naming/AccessorMethodName
# Ensure we are focused on the element
click
script = <<-JS

View File

@ -4,7 +4,6 @@ require 'capybara/session/matchers'
require 'addressable/uri'
module Capybara
##
#
# The Session class represents a single user's interaction with the system. The Session can use
@ -94,8 +93,8 @@ module Capybara
def driver
@driver ||= begin
unless Capybara.drivers.has_key?(mode)
other_drivers = Capybara.drivers.keys.map { |key| key.inspect }
unless Capybara.drivers.key?(mode)
other_drivers = Capybara.drivers.keys.map(&:inspect)
raise Capybara::DriverNotFoundError, "no driver called #{mode.inspect} was found, available drivers: #{other_drivers.join(', ')}"
end
driver = Capybara.drivers[mode].call(app)
@ -197,7 +196,7 @@ module Capybara
# Addressable doesn't support opaque URIs - we want nil here
return nil if uri.scheme == "about"
path = uri.path
path if path and not path.empty?
path if path && !path.empty?
end
##
@ -335,7 +334,7 @@ module Capybara
# @raise [Capybara::ElementNotFound] If the scope can't be found before time expires
#
def within(*args)
new_scope = if args.first.is_a?(Capybara::Node::Base) then args.first else find(*args) end
new_scope = args.first.is_a?(Capybara::Node::Base) ? args.first : find(*args)
begin
scopes.push(new_scope)
yield
@ -390,15 +389,19 @@ module Capybara
driver.switch_to_frame(frame)
scopes.push(:frame)
when :parent
if scopes.last != :frame
raise Capybara::ScopeError, "`switch_to_frame(:parent)` cannot be called from inside a descendant frame's "\
"`within` block." if scopes.last() != :frame
"`within` block."
end
scopes.pop
driver.switch_to_frame(:parent)
when :top
idx = scopes.index(:frame)
if idx
if scopes.slice(idx..-1).any? { |scope| ![:frame, nil].include?(scope) }
raise Capybara::ScopeError, "`switch_to_frame(:top)` cannot be called from inside a descendant frame's "\
"`within` block." if scopes.slice(idx..-1).any? {|scope| ![:frame, nil].include?(scope)}
"`within` block."
end
scopes.slice!(idx..-1)
driver.switch_to_frame(:top)
end
@ -477,11 +480,9 @@ module Capybara
#
def switch_to_window(window = nil, **options, &window_locator)
block_given = block_given?
if window && block_given
raise ArgumentError, "`switch_to_window` can take either a block or a window, not both"
elsif !window && !block_given
raise ArgumentError, "`switch_to_window`: either window or block should be provided"
elsif !scopes.last.nil?
raise ArgumentError, "`switch_to_window` can take either a block or a window, not both" if window && block_given
raise ArgumentError, "`switch_to_window`: either window or block should be provided" if !window && !block_given
unless scopes.last.nil?
raise Capybara::ScopeError, "`switch_to_window` is not supposed to be invoked from "\
"`within` or `within_frame` blocks."
end
@ -826,6 +827,7 @@ module Capybara
Capybara::ReadOnlySessionConfig.new(Capybara.session_options)
end
end
private
@@instance_created = false
@ -845,14 +847,12 @@ module Capybara
end
def open_file(path)
begin
require "launchy"
Launchy.open(path)
rescue LoadError
warn "File saved to #{path}."
warn "Please install the launchy gem to open the file automatically."
end
end
def prepare_path(path, extension)
path = File.expand_path(path || default_fn(extension), config.save_path)
@ -912,9 +912,7 @@ module Capybara
begin
driver.window_handles.each do |handle|
driver.switch_to_window handle
if yield
return Window.new(self, handle)
end
return Window.new(self, handle) if yield
end
rescue => e
driver.switch_to_window(original_window_handle)
@ -926,6 +924,5 @@ module Capybara
end
end
end
end
end

View File

@ -68,13 +68,13 @@ module Capybara
remove_method :app_host=
def app_host=(url)
raise ArgumentError.new("Capybara.app_host should be set to a url (http://www.example.com)") unless url.nil? || (url =~ URI::DEFAULT_PARSER.make_regexp)
raise ArgumentError, "Capybara.app_host should be set to a url (http://www.example.com)" unless url.nil? || (url =~ URI::DEFAULT_PARSER.make_regexp)
@app_host = url
end
remove_method :default_host=
def default_host=(url)
raise ArgumentError.new("Capybara.default_host should be set to a url (http://www.example.com)") unless url.nil? || (url =~ URI::DEFAULT_PARSER.make_regexp)
raise ArgumentError, "Capybara.default_host should be set to a url (http://www.example.com)" unless url.nil? || (url =~ URI::DEFAULT_PARSER.make_regexp)
@default_host = url
end

View File

@ -102,7 +102,7 @@ module Capybara
end
def eql?(other)
other.kind_of?(self.class) && @session == other.session && @handle == other.handle
other.is_a?(self.class) && @session == other.session && @handle == other.handle
end
alias_method :==, :eql?
@ -130,9 +130,7 @@ module Capybara
end
def raise_unless_current(what)
unless current?
raise Capybara::WindowError, "#{what} not current window is not possible."
end
raise Capybara::WindowError, "#{what} not current window is not possible." unless current?
end
end
end

View File

@ -2,6 +2,7 @@
require 'spec_helper'
require 'selenium-webdriver'
require 'shared_selenium_session'
require 'rspec/shared_spec_matchers'
CHROME_DRIVER = if ENV['HEADLESS'] then :selenium_chrome_headless else :selenium_chrome end
@ -12,7 +13,7 @@ CHROME_DRIVER = if ENV['HEADLESS'] then :selenium_chrome_headless else :selenium
Capybara.register_driver :selenium_chrome_clear_storage do |app|
chrome_options = {
browser: :chrome,
options: ::Selenium::WebDriver::Chrome::Options.new()
options: ::Selenium::WebDriver::Chrome::Options.new
}
chrome_options[:options].args << 'headless' if ENV['HEADLESS']
Capybara::Selenium::Driver.new(app, chrome_options.merge(clear_local_storage: true, clear_session_storage: true))
@ -31,6 +32,7 @@ Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_DRIVER.to_s, capybar
RSpec.describe "Capybara::Session with chrome" do
include Capybara::SpecHelper
include_examples "Capybara::Session", TestSessions::Chrome, CHROME_DRIVER
include_examples Capybara::RSpecMatchers, TestSessions::Chrome, CHROME_DRIVER
context "storage" do
describe "#reset!" do