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}"