Skip to content
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

Cop idea: prevent closure variables #1648

Open
thijsnado opened this issue Aug 7, 2020 · 10 comments
Open

Cop idea: prevent closure variables #1648

thijsnado opened this issue Aug 7, 2020 · 10 comments
Assignees
Labels

Comments

@thijsnado
Copy link

A common mistake I see is using closure variables instead of let statements. An example of this:

describe User do
  user = FactoryBot.create(:user)

  it "exists" do
    expect(user).not_to be_nil
  end
end

The issue with above example is now a user exists in the DB for the rest of the tests since it is not part of example transaction.

I'd be willing to work on a PR for this if you think this would be a good addition to this gem.

@pirj
Copy link
Member

pirj commented Aug 7, 2020

Good catch!
This create runs even before before(:suite) hooks.

Few things to consider:

  • calls without assignment to variables
  • fabrication gem
  • model class create! calls (can this be subject to false positives due to legitimate calls?)
  • direct calls to create/build, since it's quite popular to config.include FactoryBot::Syntax::Methods

@thijsnado
Copy link
Author

I get the feeling this should possibly be two rules:

  1. No local variables outside before/it blocks.
  2. No singleton method calls outside before/it blocks (with some configuration for allowed singletons).

I'll likely split this into two PR's.

@pirj
Copy link
Member

pirj commented Aug 8, 2020

I'd start with the second one as more impactful.
Also, I remember that variables can be quite handy in some cases, e.g.:

describe SomeConcern do
  klazz = Class.new do # a variable, not a constant because of LeakyConstant; could be `before(:context)`, but an instance var would be required then
    include SomeConcern
  end

  # examples follow
end

@thijsnado
Copy link
Author

I've always done the klass thing as a let statement. Perhaps a bit inefficient since it gets defined every test example. Is that the reason you would prefer local variable instead of let there?

@pirj
Copy link
Member

pirj commented Aug 9, 2020

One example of a legitimate usage of a variable rubocop/rubocop#8447 (comment)

inefficient since it gets defined every test example. Is that the reason

No, just because variables are simpler.

@bquorning
Copy link
Collaborator

The problem in the user = FactoryBot.create(:user) is not the local variable, but the fact that global state is changed without being reset afterwards.

@thijsnado
Copy link
Author

@pirj I think I'm going to punt on "direct calls to create/build, since it's quite popular to config.include FactoryBot::Syntax::Methods". The reason why is if you use these methods outside of an example, FactoryBot already gives you a descriptive error message stating that you should only use them within examples.

@pirj
Copy link
Member

pirj commented Aug 15, 2020

Sounds great @thijsnado 👍

@thijsnado
Copy link
Author

@pirj put up a PR, I'm getting the following failure in CI: https://app.circleci.com/pipelines/github/rubocop-hq/rubocop-rspec/460/workflows/bea51799-651f-4806-8016-12f297c9112f/jobs/16335, it looks un-related to my changes though. Any thoughts?

@pirj
Copy link
Member

pirj commented Aug 21, 2020

@thijsnado No worries, there's a fix #1014
It's caused by rubocop/rubocop#8561

@ydah ydah transferred this issue from rubocop/rubocop-rspec May 6, 2023
@ydah ydah added the cop label May 6, 2023
@pirj pirj transferred this issue from rubocop/rubocop-factory_bot May 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants