Code cleanup
This commit is contained in:
parent
2f8f15e11e
commit
744e9907a7
|
@ -214,8 +214,8 @@ module Capybara
|
|||
# @overload attach_file([locator], paths, **options)
|
||||
# @macro waiting_behavior
|
||||
#
|
||||
# @param [String] locator Which field to attach the file to
|
||||
# @param [String, Array<String>] paths The path(s) of the file(s) that will be attached, or an array of paths
|
||||
# @param [String] locator Which field to attach the file to
|
||||
# @param [String, Array<String>] paths The path(s) of the file(s) that will be attached
|
||||
#
|
||||
# @option options [Symbol] match (Capybara.match) The matching strategy to use (:one, :first, :prefer_exact, :smart).
|
||||
# @option options [Boolean] exact (Capybara.exact) Match the exact label name/contents or accept a partial match.
|
||||
|
|
|
@ -55,9 +55,7 @@ module Capybara
|
|||
|
||||
def _verify_title(title, options)
|
||||
query = Capybara::Queries::TitleQuery.new(title, options)
|
||||
synchronize(query.wait) do
|
||||
yield(query)
|
||||
end
|
||||
synchronize(query.wait) { yield(query) }
|
||||
true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
module Capybara
|
||||
module Queries
|
||||
class SelectorQuery < Queries::BaseQuery
|
||||
attr_accessor :selector, :locator, :options, :expression, :find, :negative
|
||||
|
||||
attr_reader :expression, :selector, :locator, :options
|
||||
VALID_KEYS = COUNT_KEYS + %i[text id class visible exact exact_text match wait filter_set]
|
||||
VALID_MATCH = %i[first smart prefer_exact one].freeze
|
||||
|
||||
|
@ -25,7 +24,7 @@ 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 }))
|
||||
@expression = selector.call(@locator, @options.merge(selector_config: { enable_aria_label: enable_aria_label, test_id: test_id }))
|
||||
|
||||
warn_exact_usage
|
||||
|
||||
|
@ -36,22 +35,22 @@ module Capybara
|
|||
def label; selector.label || selector.name; end
|
||||
|
||||
def description(applied = false)
|
||||
@description = +''
|
||||
if !applied || @applied_filters
|
||||
@description << 'visible ' if visible == :visible
|
||||
@description << 'non-visible ' if visible == :hidden
|
||||
desc = +''
|
||||
if !applied || applied_filters
|
||||
desc << 'visible ' if visible == :visible
|
||||
desc << 'non-visible ' if visible == :hidden
|
||||
end
|
||||
@description << "#{label} #{locator.inspect}"
|
||||
if !applied || @applied_filters
|
||||
@description << " with#{' exact' if exact_text == true} text #{options[:text].inspect}" if options[:text]
|
||||
@description << " with exact text #{exact_text}" if exact_text.is_a?(String)
|
||||
desc << "#{label} #{locator.inspect}"
|
||||
if !applied || applied_filters
|
||||
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
|
||||
@description << " with id #{options[:id]}" if options[:id]
|
||||
@description << " with classes [#{Array(options[:class]).join(',')}]" if options[:class]
|
||||
@description << selector.description(node_filters: !applied || (@applied_filters == :node), **options)
|
||||
@description << ' that also matches the custom filter block' if @filter_block && (!applied || (@applied_filters == :node))
|
||||
@description << " within #{@resolved_node.inspect}" if describe_within?
|
||||
@description
|
||||
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 << " within #{@resolved_node.inspect}" if describe_within?
|
||||
desc
|
||||
end
|
||||
|
||||
def applied_description
|
||||
|
@ -136,6 +135,10 @@ module Capybara
|
|||
|
||||
private
|
||||
|
||||
def applied_filters
|
||||
@applied_filters ||= false
|
||||
end
|
||||
|
||||
def find_selector(locator)
|
||||
selector = if locator.is_a?(Symbol)
|
||||
Selector.all.fetch(locator) { |sel_type| raise ArgumentError, "Unknown selector type (:#{sel_type})" }
|
||||
|
@ -171,7 +174,6 @@ module Capybara
|
|||
|
||||
def matches_filter_block?(node)
|
||||
return true unless @filter_block
|
||||
|
||||
if node.respond_to?(:session)
|
||||
node.session.using_wait_time(0) { @filter_block.call(node) }
|
||||
else
|
||||
|
@ -201,9 +203,9 @@ module Capybara
|
|||
unless VALID_MATCH.include?(match)
|
||||
raise ArgumentError, "invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(', ')}"
|
||||
end
|
||||
unhandled_options = @options.keys - valid_keys
|
||||
unhandled_options -= @options.keys.select do |option_name|
|
||||
expression_filters.any? { |_nmae, ef| ef.handles_option? option_name } ||
|
||||
unhandled_options = @options.keys.reject do |option_name|
|
||||
valid_keys.include?(option_name) ||
|
||||
expression_filters.any? { |_name, ef| ef.handles_option? option_name } ||
|
||||
node_filters.any? { |_name, nf| nf.handles_option? option_name }
|
||||
end
|
||||
|
||||
|
@ -266,22 +268,21 @@ module Capybara
|
|||
classes[true].to_a.map { |cl| ":not(.#{Capybara::Selector::CSS.escape(cl.slice(1))})" }).join
|
||||
end
|
||||
|
||||
def apply_expression_filters(expr)
|
||||
def apply_expression_filters(expression)
|
||||
unapplied_options = options.keys - valid_keys
|
||||
expression_filters.inject(expr) do |memo, (name, ef)|
|
||||
expression_filters.inject(expression) do |expr, (name, ef)|
|
||||
if ef.matcher?
|
||||
unapplied_options.select { |option_name| ef.handles_option?(option_name) }.each do |option_name|
|
||||
unapplied_options.select { |option_name| ef.handles_option?(option_name) }.inject(expr) do |memo, option_name|
|
||||
unapplied_options.delete(option_name)
|
||||
memo = ef.apply_filter(memo, option_name, options[option_name])
|
||||
ef.apply_filter(memo, option_name, options[option_name])
|
||||
end
|
||||
memo
|
||||
elsif options.key?(name)
|
||||
unapplied_options.delete(name)
|
||||
ef.apply_filter(memo, name, options[name])
|
||||
ef.apply_filter(expr, name, options[name])
|
||||
elsif ef.default?
|
||||
ef.apply_filter(memo, name, ef.default)
|
||||
ef.apply_filter(expr, name, ef.default)
|
||||
else
|
||||
memo
|
||||
expr
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -62,10 +62,7 @@ module Capybara
|
|||
if max_idx.nil?
|
||||
full_results[*args]
|
||||
else
|
||||
loop do
|
||||
break if @result_cache.size > max_idx
|
||||
@result_cache << @results_enum.next
|
||||
end
|
||||
load_up_to(max_idx + 1)
|
||||
@result_cache[*args]
|
||||
end
|
||||
end
|
||||
|
@ -77,40 +74,26 @@ module Capybara
|
|||
|
||||
def compare_count
|
||||
# Only check filters for as many elements as necessary to determine result
|
||||
if @query.options[:count]
|
||||
count_opt = Integer(@query.options[:count])
|
||||
loop do
|
||||
break if @result_cache.size > count_opt
|
||||
@result_cache << @results_enum.next
|
||||
end
|
||||
return @result_cache.size <=> count_opt
|
||||
if (count = @query.options[:count])
|
||||
count = Integer(count)
|
||||
return load_up_to(count + 1) <=> count
|
||||
end
|
||||
|
||||
if @query.options[:minimum]
|
||||
min_opt = Integer(@query.options[:minimum])
|
||||
begin
|
||||
@result_cache << @results_enum.next while @result_cache.size < min_opt
|
||||
rescue StopIteration
|
||||
return -1
|
||||
end
|
||||
if (min = @query.options[:minimum])
|
||||
min = Integer(min)
|
||||
return -1 if load_up_to(min) < min
|
||||
end
|
||||
|
||||
if @query.options[:maximum]
|
||||
max_opt = Integer(@query.options[:maximum])
|
||||
loop do
|
||||
return 1 if @result_cache.size > max_opt
|
||||
@result_cache << @results_enum.next
|
||||
end
|
||||
if (max = @query.options[:maximum])
|
||||
max = Integer(max)
|
||||
return 1 if load_up_to(max + 1) > max
|
||||
end
|
||||
|
||||
if @query.options[:between]
|
||||
min, max = @query.options[:between].minmax
|
||||
loop do
|
||||
break if @result_cache.size > max
|
||||
@result_cache << @results_enum.next
|
||||
end
|
||||
return 0 if @query.options[:between].include? @result_cache.size
|
||||
return @result_cache.size <=> min
|
||||
if (between = @query.options[:between])
|
||||
min, max = between.minmax
|
||||
size = load_up_to(max + 1)
|
||||
return 0 if between.include? size
|
||||
return size <=> min
|
||||
end
|
||||
|
||||
0
|
||||
|
@ -144,6 +127,14 @@ module Capybara
|
|||
|
||||
private
|
||||
|
||||
def load_up_to(num)
|
||||
loop do
|
||||
break if @result_cache.size >= num
|
||||
@result_cache << @results_enum.next
|
||||
end
|
||||
@result_cache.size
|
||||
end
|
||||
|
||||
def full_results
|
||||
loop { @result_cache << @results_enum.next }
|
||||
@result_cache
|
||||
|
|
|
@ -185,7 +185,6 @@ module Capybara
|
|||
@match = nil
|
||||
@label = nil
|
||||
@failure_message = nil
|
||||
@description = nil
|
||||
@format = nil
|
||||
@expression = nil
|
||||
@expression_filters = {}
|
||||
|
|
|
@ -49,7 +49,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|||
@app = app
|
||||
@browser = nil
|
||||
@exit_status = nil
|
||||
@frame_handles = {}
|
||||
@frame_handles = Hash.new { |hash, handle| hash[handle] = [] }
|
||||
@options = DEFAULT_OPTIONS.merge(options)
|
||||
@node_class = ::Capybara::Selenium::Node
|
||||
end
|
||||
|
@ -170,19 +170,19 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|||
end
|
||||
|
||||
def switch_to_frame(frame)
|
||||
handles = @frame_handles[current_window_handle]
|
||||
case frame
|
||||
when :top
|
||||
@frame_handles[browser.window_handle] = []
|
||||
handles.clear
|
||||
browser.switch_to.default_content
|
||||
when :parent
|
||||
# would love to use browser.switch_to.parent_frame here
|
||||
# but it has an issue if the current frame is removed from within it
|
||||
@frame_handles[browser.window_handle].pop
|
||||
handles.pop
|
||||
browser.switch_to.default_content
|
||||
@frame_handles[browser.window_handle].each { |fh| browser.switch_to.frame(fh) }
|
||||
handles.each { |fh| browser.switch_to.frame(fh) }
|
||||
else
|
||||
@frame_handles[browser.window_handle] ||= []
|
||||
@frame_handles[browser.window_handle] << frame.native
|
||||
handles << frame.native
|
||||
browser.switch_to.frame(frame.native)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Selenium specific implementation of the Capybara::Driver::Node API
|
||||
class Capybara::Selenium::Node < Capybara::Driver::Node
|
||||
def visible_text
|
||||
native.text
|
||||
|
@ -82,13 +83,11 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|||
end
|
||||
|
||||
def click(keys = [], **options)
|
||||
if keys.empty? && !coords?(options)
|
||||
native.click
|
||||
else
|
||||
scroll_if_needed do
|
||||
action_with_modifiers(keys, options) do |action|
|
||||
coords?(options) ? action.click : action.click(native)
|
||||
end
|
||||
click_options = ClickOptions.new(keys, options)
|
||||
return native.click if click_options.empty?
|
||||
scroll_if_needed do
|
||||
action_with_modifiers(click_options) do |action|
|
||||
click_options.coords? ? action.click : action.click(native)
|
||||
end
|
||||
end
|
||||
rescue StandardError => err
|
||||
|
@ -101,17 +100,19 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|||
end
|
||||
|
||||
def right_click(keys = [], **options)
|
||||
click_options = ClickOptions.new(keys, options)
|
||||
scroll_if_needed do
|
||||
action_with_modifiers(keys, options) do |action|
|
||||
coords?(options) ? action.context_click : action.context_click(native)
|
||||
action_with_modifiers(click_options) do |action|
|
||||
click_options.coords? ? action.context_click : action.context_click(native)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def double_click(keys = [], **options)
|
||||
click_options = ClickOptions.new(keys, options)
|
||||
scroll_if_needed do
|
||||
action_with_modifiers(keys, options) do |action|
|
||||
coords?(options) ? action.double_click : action.double_click(native)
|
||||
action_with_modifiers(click_options) do |action|
|
||||
click_options.coords? ? action.double_click : action.double_click(native)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -121,11 +122,11 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|||
end
|
||||
|
||||
def hover
|
||||
scroll_if_needed { driver.browser.action.move_to(native).perform }
|
||||
scroll_if_needed { browser_action.move_to(native).perform }
|
||||
end
|
||||
|
||||
def drag_to(element)
|
||||
scroll_if_needed { driver.browser.action.drag_and_drop(native, element.native).perform }
|
||||
scroll_if_needed { browser_action.drag_and_drop(native, element.native).perform }
|
||||
end
|
||||
|
||||
def tag_name
|
||||
|
@ -192,10 +193,6 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|||
|
||||
private
|
||||
|
||||
def coords?(options)
|
||||
options[:x] && options[:y]
|
||||
end
|
||||
|
||||
def boolean_attr(val)
|
||||
val && (val != 'false')
|
||||
end
|
||||
|
@ -206,22 +203,23 @@ private
|
|||
end
|
||||
|
||||
def set_text(value, clear: nil, **_unused)
|
||||
if value.to_s.empty? && clear.nil?
|
||||
value = value.to_s
|
||||
if value.empty? && clear.nil?
|
||||
native.clear
|
||||
elsif clear == :backspace
|
||||
# Clear field by sending the correct number of backspace keys.
|
||||
backspaces = [:backspace] * self.value.to_s.length
|
||||
send_keys(*([:end] + backspaces + [value.to_s]))
|
||||
send_keys(*([:end] + backspaces + [value]))
|
||||
elsif clear == :none
|
||||
send_keys(value.to_s)
|
||||
send_keys(value)
|
||||
elsif clear.is_a? Array
|
||||
send_keys(*clear, value.to_s)
|
||||
send_keys(*clear, value)
|
||||
else
|
||||
# Clear field by JavaScript assignment of the value property.
|
||||
# Script can change a readonly element which user input cannot, so
|
||||
# don't execute if readonly.
|
||||
driver.execute_script "arguments[0].value = ''", self
|
||||
send_keys(value.to_s)
|
||||
send_keys(value)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -248,21 +246,24 @@ private
|
|||
end
|
||||
|
||||
def set_date(value) # rubocop:disable Naming/AccessorMethodName
|
||||
return set_text(value) if value.is_a?(String) || !value.respond_to?(:to_date)
|
||||
value = SettableValue.new(value)
|
||||
return set_text(value) unless value.dateable?
|
||||
# TODO: this would be better if locale can be detected and correct keystrokes sent
|
||||
update_value_js(value.to_date.strftime('%Y-%m-%d'))
|
||||
update_value_js(value.to_date_str)
|
||||
end
|
||||
|
||||
def set_time(value) # rubocop:disable Naming/AccessorMethodName
|
||||
return set_text(value) if value.is_a?(String) || !value.respond_to?(:to_time)
|
||||
value = SettableValue.new(value)
|
||||
return set_text(value) unless value.timeable?
|
||||
# TODO: this would be better if locale can be detected and correct keystrokes sent
|
||||
update_value_js(value.to_time.strftime('%H:%M'))
|
||||
update_value_js(value.to_time_str)
|
||||
end
|
||||
|
||||
def set_datetime_local(value) # rubocop:disable Naming/AccessorMethodName
|
||||
return set_text(value) if value.is_a?(String) || !value.respond_to?(:to_time)
|
||||
value = SettableValue.new(value)
|
||||
return set_text(value) unless value.timeable?
|
||||
# TODO: this would be better if locale can be detected and correct keystrokes sent
|
||||
update_value_js(value.to_time.strftime('%Y-%m-%dT%H:%M'))
|
||||
update_value_js(value.to_datetime_str)
|
||||
end
|
||||
|
||||
def update_value_js(value)
|
||||
|
@ -301,34 +302,33 @@ private
|
|||
# if we use the faster direct send_keys. For now just send_keys to the element
|
||||
# we've already focused.
|
||||
# native.send_keys(value.to_s)
|
||||
driver.browser.action.send_keys(value.to_s).perform
|
||||
browser_action.send_keys(value.to_s).perform
|
||||
end
|
||||
|
||||
def action_with_modifiers(keys, x: nil, y: nil)
|
||||
actions = driver.browser.action
|
||||
actions.move_to(native, x, y)
|
||||
modifiers_down(actions, keys)
|
||||
def action_with_modifiers(click_options)
|
||||
actions = browser_action.move_to(native, *click_options.coords)
|
||||
modifiers_down(actions, click_options.keys)
|
||||
yield actions
|
||||
modifiers_up(actions, keys)
|
||||
modifiers_up(actions, click_options.keys)
|
||||
actions.perform
|
||||
ensure
|
||||
act = driver.browser.action
|
||||
act = browser_action
|
||||
act.release_actions if act.respond_to?(:release_actions)
|
||||
end
|
||||
|
||||
def modifiers_down(actions, keys)
|
||||
keys.each do |key|
|
||||
key = case key
|
||||
when :ctrl then :control
|
||||
when :command, :cmd then :meta
|
||||
else
|
||||
key
|
||||
end
|
||||
actions.key_down(key)
|
||||
end
|
||||
each_key(keys) { |key| actions.key_down(key) }
|
||||
end
|
||||
|
||||
def modifiers_up(actions, keys)
|
||||
each_key(keys) { |key| actions.key_up(key) }
|
||||
end
|
||||
|
||||
def browser_action
|
||||
driver.browser.action
|
||||
end
|
||||
|
||||
def each_key(keys)
|
||||
keys.each do |key|
|
||||
key = case key
|
||||
when :ctrl then :control
|
||||
|
@ -336,7 +336,60 @@ private
|
|||
else
|
||||
key
|
||||
end
|
||||
actions.key_up(key)
|
||||
yield key
|
||||
end
|
||||
end
|
||||
|
||||
# SettableValue encapsulates time/date field formatting
|
||||
class SettableValue
|
||||
attr_reader :value
|
||||
|
||||
def initialize(value)
|
||||
@value = value
|
||||
end
|
||||
|
||||
def dateable?
|
||||
!value.is_a?(String) && value.respond_to?(:to_date)
|
||||
end
|
||||
|
||||
def to_date_str
|
||||
value.to_date.strftime('%Y-%m-%d')
|
||||
end
|
||||
|
||||
def timeable?
|
||||
!value.is_a?(String) && value.respond_to?(:to_time)
|
||||
end
|
||||
|
||||
def to_time_str
|
||||
value.to_time.strftime('%H:%M')
|
||||
end
|
||||
|
||||
def to_datetime_str
|
||||
value.to_time.strftime('%Y-%m-%dT%H:%M')
|
||||
end
|
||||
end
|
||||
private_constant :SettableValue
|
||||
|
||||
# ClickOptions encapsulates click option logic
|
||||
class ClickOptions
|
||||
attr_reader :keys, :options
|
||||
|
||||
def initialize(keys, options)
|
||||
@keys = keys
|
||||
@options = options
|
||||
end
|
||||
|
||||
def coords?
|
||||
options[:x] && options[:y]
|
||||
end
|
||||
|
||||
def coords
|
||||
[options[:x], options[:y]]
|
||||
end
|
||||
|
||||
def empty?
|
||||
keys.empty? && !coords?
|
||||
end
|
||||
end
|
||||
private_constant :ClickOptions
|
||||
end
|
||||
|
|
|
@ -13,7 +13,7 @@ class Capybara::Selenium::ChromeNode < Capybara::Selenium::Node
|
|||
def drag_to(element)
|
||||
return super unless self[:draggable] == 'true'
|
||||
|
||||
scroll_if_needed { driver.browser.action.click_and_hold(native).perform }
|
||||
scroll_if_needed { browser_action.click_and_hold(native).perform }
|
||||
driver.execute_script HTML5_DRAG_DROP_SCRIPT, self, element
|
||||
end
|
||||
|
||||
|
|
|
@ -47,17 +47,15 @@ class Capybara::Selenium::MarionetteNode < Capybara::Selenium::Node
|
|||
return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none? { |arg| arg.is_a? Array }
|
||||
|
||||
native.click
|
||||
actions = driver.browser.action
|
||||
args.each do |keys|
|
||||
args.each_with_object(browser_action) do |keys, actions|
|
||||
_send_keys(keys, actions)
|
||||
end
|
||||
actions.perform
|
||||
end.perform
|
||||
end
|
||||
|
||||
def drag_to(element)
|
||||
return super unless (browser_version >= 62.0) && (self[:draggable] == 'true')
|
||||
|
||||
scroll_if_needed { driver.browser.action.click_and_hold(native).perform }
|
||||
scroll_if_needed { browser_action.click_and_hold(native).perform }
|
||||
driver.execute_script HTML5_DRAG_DROP_SCRIPT, self, element
|
||||
end
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ module Capybara
|
|||
end
|
||||
|
||||
def reset_error!
|
||||
middleware.error = nil
|
||||
middleware.clear_error
|
||||
end
|
||||
|
||||
def error
|
||||
|
|
|
@ -20,7 +20,7 @@ module Capybara
|
|||
end
|
||||
end
|
||||
|
||||
attr_accessor :error
|
||||
attr_reader :error
|
||||
|
||||
def initialize(app, server_errors, extra_middleware = [])
|
||||
@app = app
|
||||
|
@ -35,6 +35,10 @@ module Capybara
|
|||
@counter.value.positive?
|
||||
end
|
||||
|
||||
def clear_error
|
||||
@error = nil
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if env['PATH_INFO'] == '/__identify__'
|
||||
[200, {}, [@app.object_id.to_s]]
|
||||
|
|
|
@ -137,7 +137,7 @@ module Capybara
|
|||
# Raise errors encountered in the server
|
||||
#
|
||||
def raise_server_error!
|
||||
return if @server.nil? || !@server.error
|
||||
return unless @server&.error
|
||||
# Force an explanation for the error being raised as the exception cause
|
||||
begin
|
||||
if config.raise_server_errors
|
||||
|
|
|
@ -323,7 +323,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
|
|||
end
|
||||
end
|
||||
|
||||
describe 'Capybara#disable_animation', :focus_ do
|
||||
describe 'Capybara#disable_animation' do
|
||||
context 'when set to `true`' do
|
||||
before(:context) do # rubocop:disable RSpec/BeforeAfterAll
|
||||
# NOTE: Although Capybara.SpecHelper.reset! sets Capybara.disable_animation to false,
|
||||
|
|
Loading…
Reference in New Issue