lib/rubocop/cop/capybara/specific_finders.rb in rubocop-capybara-2.17.0 vs lib/rubocop/cop/capybara/specific_finders.rb in rubocop-capybara-2.17.1
- old
+ new
@@ -25,41 +25,76 @@
# @!method find_argument(node)
def_node_matcher :find_argument, <<~PATTERN
(send _ :find (str $_) ...)
PATTERN
+ # @!method class_options(node)
+ def_node_search :class_options, <<~PATTERN
+ (pair (sym :class) $_ ...)
+ PATTERN
+
def on_send(node)
find_argument(node) do |arg|
+ next if CssSelector.pseudo_classes(arg).any?
next if CssSelector.multiple_selectors?(arg)
on_attr(node, arg) if attribute?(arg)
on_id(node, arg) if CssSelector.id?(arg)
end
end
private
def on_attr(node, arg)
- return unless (id = CssSelector.attributes(arg)['id'])
+ attrs = CssSelector.attributes(arg)
+ return unless (id = attrs['id'])
+ return if attrs['class']
register_offense(node, replaced_arguments(arg, id))
end
def on_id(node, arg)
- register_offense(node, "'#{arg.to_s.delete('#')}'")
+ return if CssSelector.attributes(arg).any?
+
+ id = CssSelector.id(arg)
+ register_offense(node, "'#{id}'",
+ CssSelector.classes(arg.sub("##{id}", '')))
end
def attribute?(arg)
CssSelector.attribute?(arg) &&
- CssSelector.common_attributes?(arg)
+ CapybaraHelp.common_attributes?(arg)
end
- def register_offense(node, arg_replacement)
+ def register_offense(node, id, classes = [])
add_offense(offense_range(node)) do |corrector|
corrector.replace(node.loc.selector, 'find_by_id')
corrector.replace(node.first_argument.loc.expression,
- arg_replacement)
+ id.delete('\\'))
+ unless classes.compact.empty?
+ autocorrect_classes(corrector, node, classes)
+ end
end
+ end
+
+ def autocorrect_classes(corrector, node, classes)
+ if (options = class_options(node).first)
+ append_options(classes, options)
+ corrector.replace(options, classes.to_s)
+ else
+ corrector.insert_after(node.first_argument,
+ keyword_argument_class(classes))
+ end
+ end
+
+ def append_options(classes, options)
+ classes << options.value if options.str_type?
+ options.each_value { |v| classes << v.value } if options.array_type?
+ end
+
+ def keyword_argument_class(classes)
+ value = classes.size > 1 ? classes.to_s : "'#{classes.first}'"
+ ", class: #{value}"
end
def replaced_arguments(arg, id)
options = to_options(CssSelector.attributes(arg))
options.empty? ? id : "#{id}, #{options}"