Skip to content

Commit d9a818a

Browse files
authored
Merge pull request #1779 from G-Rath/support-assert-includes
feat: support `*_includes` assertions in `RSpec/Rails/MinitestAssertions`
2 parents 5bc81e9 + 95972e2 commit d9a818a

File tree

4 files changed

+128
-3
lines changed

4 files changed

+128
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
## Master (Unreleased)
44

55
- Add support for `assert_empty`, `assert_not_empty` and `refute_empty` to `RSpec/Rails/MinitestAssertions`. ([@ydah])
6-
- Support correcting `assert_nil` and `refute_nil` in `RSpec/Rails/MinitestAssertions`. ([@G-Rath])
7-
- Support correcting `assert_not_equal` and `assert_not_equal` in `RSpec/Rails/MinitestAssertions`. ([@G-Rath])
6+
- Support correcting `*_includes` assertions in `RSpec/Rails/MinitestAssertions`. ([@G-Rath])
7+
- Support correcting `assert_not_equal` and `assert_not_nil` in `RSpec/Rails/MinitestAssertions`. ([@G-Rath])
88
- Fix a false positive for `RSpec/ExpectActual` when used with rspec-rails routing matchers. ([@naveg])
99
- Add new `RSpec/RepeatedSubjectCall` cop. ([@drcapulet])
1010

docs/modules/ROOT/pages/cops_rspecrails.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,13 +255,15 @@ Check if using Minitest matchers.
255255
# bad
256256
assert_equal(a, b)
257257
assert_equal a, b, "must be equal"
258+
assert_not_includes a, b
258259
refute_equal(a, b)
259260
assert_nil a
260261
refute_empty(b)
261262
262263
# good
263264
expect(b).to eq(a)
264265
expect(b).to(eq(a), "must be equal")
266+
expect(a).not_to include(b)
265267
expect(b).not_to eq(a)
266268
expect(a).to eq(nil)
267269
expect(a).not_to be_empty

lib/rubocop/cop/rspec_rails/minitest_assertions.rb

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ module Rails
1010
# # bad
1111
# assert_equal(a, b)
1212
# assert_equal a, b, "must be equal"
13+
# assert_not_includes a, b
1314
# refute_equal(a, b)
1415
# assert_nil a
1516
# refute_empty(b)
1617
#
1718
# # good
1819
# expect(b).to eq(a)
1920
# expect(b).to(eq(a), "must be equal")
21+
# expect(a).not_to include(b)
2022
# expect(b).not_to eq(a)
2123
# expect(a).to eq(nil)
2224
# expect(a).not_to be_empty
@@ -28,11 +30,14 @@ class MinitestAssertions < Base
2830
RESTRICT_ON_SEND = %i[
2931
assert_equal
3032
assert_not_equal
33+
assert_includes
34+
assert_not_includes
3135
assert_nil
3236
assert_not_nil
3337
assert_empty
3438
assert_not_empty
3539
refute_equal
40+
refute_includes
3641
refute_nil
3742
refute_empty
3843
].freeze
@@ -42,6 +47,11 @@ class MinitestAssertions < Base
4247
(send nil? {:assert_equal :assert_not_equal :refute_equal} $_ $_ $_?)
4348
PATTERN
4449

50+
# @!method minitest_includes(node)
51+
def_node_matcher :minitest_includes, <<~PATTERN
52+
(send nil? {:assert_includes :assert_not_includes :refute_includes} $_ $_ $_?)
53+
PATTERN
54+
4555
# @!method minitest_nil(node)
4656
def_node_matcher :minitest_nil, <<~PATTERN
4757
(send nil? {:assert_nil :assert_not_nil :refute_nil} $_ $_?)
@@ -52,12 +62,17 @@ class MinitestAssertions < Base
5262
(send nil? {:assert_empty :assert_not_empty :refute_empty} $_ $_?)
5363
PATTERN
5464

55-
def on_send(node) # rubocop:disable Metrics/MethodLength
65+
def on_send(node) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
5666
minitest_equal(node) do |expected, actual, failure_message|
5767
on_assertion(node, EqualAssertion.new(expected, actual,
5868
failure_message.first))
5969
end
6070

71+
minitest_includes(node) do |collection, expected, failure_message|
72+
on_assertion(node, IncludesAssertion.new(collection, expected,
73+
failure_message.first))
74+
end
75+
6176
minitest_nil(node) do |actual, failure_message|
6277
on_assertion(node, NilAssertion.new(actual,
6378
failure_message.first))
@@ -99,6 +114,28 @@ def replaced(node)
99114
end
100115
end
101116

117+
# :nodoc:
118+
class IncludesAssertion
119+
def initialize(collection, expected, fail_message)
120+
@collection = collection
121+
@expected = expected
122+
@fail_message = fail_message
123+
end
124+
125+
def replaced(node)
126+
a_source = @collection.source
127+
b_source = @expected.source
128+
129+
runner = node.method?(:assert_includes) ? 'to' : 'not_to'
130+
if @fail_message.nil?
131+
"expect(#{a_source}).#{runner} include(#{b_source})"
132+
else
133+
"expect(#{a_source}).#{runner}(include(#{b_source})," \
134+
" #{@fail_message.source})"
135+
end
136+
end
137+
end
138+
102139
# :nodoc:
103140
class NilAssertion
104141
def initialize(actual, fail_message)

spec/rubocop/cop/rspec_rails/minitest_assertions_spec.rb

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,92 @@
8484
end
8585
end
8686

87+
context 'with includes assertions' do
88+
it 'registers an offense when using `assert_includes`' do
89+
expect_offense(<<~RUBY)
90+
assert_includes(a, b)
91+
^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to include(b)`.
92+
RUBY
93+
94+
expect_correction(<<~RUBY)
95+
expect(a).to include(b)
96+
RUBY
97+
end
98+
99+
it 'registers an offense when using `assert_includes` with ' \
100+
'no parentheses' do
101+
expect_offense(<<~RUBY)
102+
assert_includes a, b
103+
^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to include(b)`.
104+
RUBY
105+
106+
expect_correction(<<~RUBY)
107+
expect(a).to include(b)
108+
RUBY
109+
end
110+
111+
it 'registers an offense when using `assert_includes` with ' \
112+
'failure message' do
113+
expect_offense(<<~RUBY)
114+
assert_includes a, b, "must be include"
115+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).to(include(b), "must be include")`.
116+
RUBY
117+
118+
expect_correction(<<~RUBY)
119+
expect(a).to(include(b), "must be include")
120+
RUBY
121+
end
122+
123+
it 'registers an offense when using `assert_includes` with ' \
124+
'multi-line arguments' do
125+
expect_offense(<<~RUBY)
126+
assert_includes(a,
127+
^^^^^^^^^^^^^^^^^^ Use `expect(a).to(include(b), "must be include")`.
128+
b,
129+
"must be include")
130+
RUBY
131+
132+
expect_correction(<<~RUBY)
133+
expect(a).to(include(b), "must be include")
134+
RUBY
135+
end
136+
137+
it 'registers an offense when using `assert_not_includes`' do
138+
expect_offense(<<~RUBY)
139+
assert_not_includes a, b
140+
^^^^^^^^^^^^^^^^^^^^^^^^ Use `expect(a).not_to include(b)`.
141+
RUBY
142+
143+
expect_correction(<<~RUBY)
144+
expect(a).not_to include(b)
145+
RUBY
146+
end
147+
148+
it 'registers an offense when using `refute_includes`' do
149+
expect_offense(<<~RUBY)
150+
refute_includes a, b
151+
^^^^^^^^^^^^^^^^^^^^ Use `expect(a).not_to include(b)`.
152+
RUBY
153+
154+
expect_correction(<<~RUBY)
155+
expect(a).not_to include(b)
156+
RUBY
157+
end
158+
159+
it 'does not register an offense when using `expect(a).to include(b)`' do
160+
expect_no_offenses(<<~RUBY)
161+
expect(a).to include(b)
162+
RUBY
163+
end
164+
165+
it 'does not register an offense when ' \
166+
'using `expect(a).not_to include(b)`' do
167+
expect_no_offenses(<<~RUBY)
168+
expect(a).not_to include(b)
169+
RUBY
170+
end
171+
end
172+
87173
context 'with nil assertions' do
88174
it 'registers an offense when using `assert_nil`' do
89175
expect_offense(<<~RUBY)

0 commit comments

Comments
 (0)