Class: RuboCop::Cop::Guardrails::NoTestStrings

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/guardrails/no_test_strings.rb

Overview

Prevents string literals in test assertions and finders.

Asserting on string copy or finding records by string values makes tests brittle — when copy changes, unrelated tests break. Use i18n keys, element IDs, predicate methods, or fixtures instead.

Flags:

  • Any ‘assert_*` or `refute_*` method with a string literal argument, except those where strings are part of the API (expressions, selectors, paths, etc.)

  • ‘find_by` / `where` with string literal values

Examples:

# bad
assert_equal "Published", card.status
assert_includes response.body, "Welcome back"
assert_match "Success", response.body
assert_flash "Card published"
card = Card.find_by(title: "Logo Design")

# good
assert card.published?
assert_select "#flash-notice"
assert_difference "Card.count" do ... end
assert_equal I18n.t("flash.success"), flash[:notice]
card = cards(:logo)

Constant Summary collapse

MSG_ASSERTION =
'Avoid hardcoded strings in assertions. ' \
'Assert against the source value, an i18n key, or a predicate.'
MSG_FINDER =
'Avoid finding records by string values. Use fixtures instead.'
EXCLUDED_ASSERTIONS =

Assertions where string arguments are part of the API (Ruby expressions, CSS selectors, paths, etc.) — not copy.

%i[
  assert_changes
  assert_no_changes
  assert_deprecated
  assert_difference
  assert_no_difference
  assert_dom
  assert_not_dom
  assert_not_select
  assert_generates
  assert_path_exists
  assert_recognizes
  assert_routing
  assert_select
  assert_template
  refute_dom
  refute_path_exists
  refute_select
].to_set.freeze

Instance Method Summary collapse

Instance Method Details

#on_send(node) ⇒ Object Also known as: on_csend



60
61
62
63
64
65
66
67
68
# File 'lib/rubocop/cop/guardrails/no_test_strings.rb', line 60

def on_send(node)
  method = node.method_name

  if flagged_assertion?(method)
    add_offense(node, message: MSG_ASSERTION) if any_string_argument?(node)
  elsif %i[find_by where].include?(method)
    add_offense(node, message: MSG_FINDER) if any_string_hash_value?(node)
  end
end