Skip to content

Commit 820ce0b

Browse files
committed
feat: support correcting assert_redirected_to in RSpec/Rails/MinitestAssertions
1 parent 1416aa0 commit 820ce0b

File tree

4 files changed

+128
-0
lines changed

4 files changed

+128
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Master (Unreleased)
44

55
- Fix a false positive for `RspecRails/NegationBeValid` when use `to_not`. ([@ydah])
6+
- Supporting correcting `assest_redirected_to` in `RSpec/Rails/MinitestAssertions`. ([@nzlaura])
67

78
## 2.32.0 (2025-11-12)
89

docs/modules/ROOT/pages/cops_rspecrails.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ refute_empty(b)
365365
assert_true(a)
366366
assert_false(a)
367367
assert_response :ok
368+
assert_redirected_to '/users'
368369
369370
# good
370371
expect(b).to eq(a)
@@ -376,6 +377,7 @@ expect(a).not_to be_empty
376377
expect(a).to be(true)
377378
expect(a).to be(false)
378379
expect(response).to have_http_status(:ok)
380+
expect(response).to redirect_to('/users')
379381
----
380382
381383
[#references-rspecrailsminitestassertions]

lib/rubocop/cop/rspec_rails/minitest_assertions.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module RSpecRails
1919
# assert_true(a)
2020
# assert_false(a)
2121
# assert_response :ok
22+
# assert_redirected_to '/users'
2223
#
2324
# # good
2425
# expect(b).to eq(a)
@@ -30,6 +31,7 @@ module RSpecRails
3031
# expect(a).to be(true)
3132
# expect(a).to be(false)
3233
# expect(response).to have_http_status(:ok)
34+
# expect(response).to redirect_to('/users')
3335
#
3436
class MinitestAssertions < ::RuboCop::Cop::Base
3537
extend AutoCorrector
@@ -339,6 +341,28 @@ def assertion
339341
end
340342
end
341343

344+
# :nodoc:
345+
class RedirectAssertion < BasicAssertion
346+
MATCHERS = %i[
347+
assert_redirected_to
348+
].freeze
349+
350+
ASSERT_ACTUAL_NODE = Struct.new(:source).new('response')
351+
352+
# @!method self.minitest_assertion(node)
353+
def_node_matcher 'self.minitest_assertion', <<~PATTERN # rubocop:disable InternalAffairs/NodeMatcherDirective
354+
(send nil? {:assert_redirected_to} $_ $_?)
355+
PATTERN
356+
357+
def self.match(expected, failure_message)
358+
new(expected, ASSERT_ACTUAL_NODE, failure_message.first)
359+
end
360+
361+
def assertion
362+
"redirect_to(#{expected})"
363+
end
364+
end
365+
342366
MSG = 'Use `%<prefer>s`.'
343367

344368
# TODO: replace with `BasicAssertion.subclasses` in Ruby 3.1+

spec/rubocop/cop/rspec_rails/minitest_assertions_spec.rb

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,4 +1033,105 @@
10331033
RUBY
10341034
end
10351035
end
1036+
1037+
context 'with redirect assertions' do
1038+
it 'registers an offense when using `assert_redirected_to` with a path' do
1039+
expect_offense(<<~RUBY)
1040+
assert_redirected_to '/users'
1041+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(response).to redirect_to('/users')`.
1042+
RUBY
1043+
1044+
expect_correction(<<~RUBY)
1045+
expect(response).to redirect_to('/users')
1046+
RUBY
1047+
end
1048+
1049+
# rubocop:disable Layout/LineLength
1050+
it 'registers an offense when using `assert_redirected_to` with parentheses' do
1051+
# rubocop:enable Layout/LineLength
1052+
expect_offense(<<~RUBY)
1053+
assert_redirected_to('/users')
1054+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(response).to redirect_to('/users')`.
1055+
RUBY
1056+
1057+
expect_correction(<<~RUBY)
1058+
expect(response).to redirect_to('/users')
1059+
RUBY
1060+
end
1061+
1062+
it 'registers an offense when using `assert_redirected_to` with ' \
1063+
'controller and action' do
1064+
expect_offense(<<~RUBY)
1065+
assert_redirected_to controller: 'users', action: 'show'
1066+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(response).to redirect_to(controller: 'users', action: 'show')`.
1067+
RUBY
1068+
1069+
expect_correction(<<~RUBY)
1070+
expect(response).to redirect_to(controller: 'users', action: 'show')
1071+
RUBY
1072+
end
1073+
1074+
it 'registers an offense when using `assert_redirected_to` with ' \
1075+
'failure message' do
1076+
expect_offense(<<~RUBY)
1077+
assert_redirected_to '/users', "expected redirect to users"
1078+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(response).to(redirect_to('/users'), "expected redirect to users")`.
1079+
RUBY
1080+
1081+
expect_correction(<<~RUBY)
1082+
expect(response).to(redirect_to('/users'), "expected redirect to users")
1083+
RUBY
1084+
end
1085+
1086+
it 'registers an offense when using `assert_redirected_to` with ' \
1087+
'multi-line arguments' do
1088+
expect_offense(<<~RUBY)
1089+
assert_redirected_to('/users',
1090+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(response).to(redirect_to('/users'), "expected redirect to users")`.
1091+
"expected redirect to users")
1092+
RUBY
1093+
1094+
expect_correction(<<~RUBY)
1095+
expect(response).to(redirect_to('/users'), "expected redirect to users")
1096+
RUBY
1097+
end
1098+
1099+
it 'registers an offense when using `assert_redirected_to` with ' \
1100+
'a URL' do
1101+
expect_offense(<<~RUBY)
1102+
assert_redirected_to 'http://example.com/users'
1103+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(response).to redirect_to('http://example.com/users')`.
1104+
RUBY
1105+
1106+
expect_correction(<<~RUBY)
1107+
expect(response).to redirect_to('http://example.com/users')
1108+
RUBY
1109+
end
1110+
1111+
it 'registers an offense when using `assert_redirected_to` with ' \
1112+
'a named route' do
1113+
expect_offense(<<~RUBY)
1114+
assert_redirected_to users_path
1115+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(response).to redirect_to(users_path)`.
1116+
RUBY
1117+
1118+
expect_correction(<<~RUBY)
1119+
expect(response).to redirect_to(users_path)
1120+
RUBY
1121+
end
1122+
1123+
it 'does not register an offense when using ' \
1124+
'`expect(response).to redirect_to`' do
1125+
expect_no_offenses(<<~RUBY)
1126+
expect(response).to redirect_to('/users')
1127+
RUBY
1128+
end
1129+
1130+
it 'does not register an offense when using ' \
1131+
'`expect(response).to redirect_to` with controller and action' do
1132+
expect_no_offenses(<<~RUBY)
1133+
expect(response).to redirect_to(controller: 'users', action: 'show')
1134+
RUBY
1135+
end
1136+
end
10361137
end

0 commit comments

Comments
 (0)