-
-
Notifications
You must be signed in to change notification settings - Fork 281
Add new cop RSpec/LeakyLocalVariable
#2101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Here's the cop report for real-world-rspec. I wrote a custom formatter which prints the URL to the file and line on the remote, so you can go through it and see offenses directly on GH. There are 866 offenses for all codebases in that repo. Report
|
next unless part_of_example_scope?(reference) | ||
next if permitted_argument?(reference) | ||
|
||
add_offense(assignment.node) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initially I added the offense to the reference node, but that created offense noise (if an offending variable is referenced many times, there will be many offenses). An offense on the assignment node reduces that noise, but it may not be clear which reference triggered the offense. Let me know what you think is the better option.
Here's an example:
user = create(:user)
# ^^^^^^^^^^^^^^^^^^^^ assignment offense (only one)
before do
user.update(admin: true)
# ^^^^ reference offense
user.flag!
# ^^^^ reference offense (repeated for all references)
end
2db2779
to
1c78177
Compare
1c78177
to
c791895
Compare
The problem is not the variable, but a call to factory outside of the example, made outside of the example lifecycle. Variables come handy at times, because you can’t reasonably use constants (see LeakyConstant). Would you agree to re-target the cop to catch those out-of-scope factory calls? |
I agree that that's a problem, but I don't think it's the problem. A local variable that's not a call to a factory can still be equally problematic, e.g.: foo = 'string'
it 'does something' do
foo << 'modification'
expect(foo).to eq('stringmodification')
end
it 'does something else' do
expect(foo).to eq('string') # this example can fail depending on the example order
end I would agree that some examples in there are harmless, but a lot of them are unnecessarily made local variables. To give a few examples:
Most of the examples in the report follow this pattern. Also, despite being harmless, I think that |
Adds a new cop to register offenses for local variables assigned outside of examples, but referenced within them. In such cases, local variables are shared state, and they can make tests non-deterministic if they run in random order.
The cop will register offenses for:
The cop does not register offenses when local variable is:
I think this closes #1648. There are some other ideas in there, but I believe this cop solves the major pain point (which is shared state between examples through local variables).
Before submitting the PR make sure the following are checked:
config/default.yml
.Enabled: pending
inconfig/default.yml
.Enabled: true
in.rubocop.yml
.VersionAdded: "<<next>>"
indefault/config.yml
.