-
-
Notifications
You must be signed in to change notification settings - Fork 5
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
Add RSpecRails/Timecop cop #48
base: master
Are you sure you want to change the base?
Conversation
This cop makes `Timecop` illegal, in favour of `ActiveSupport::Testing::TimeHelpers`. Specifically, - `Timecop.freeze` should be replaced with `freeze_time` (autocorrected) - `Timecop.freeze(...)` should be replaced with `travel` or `travel_to` - `Timecop.return` should be replaced with `travel_back` or `unfreeze_time` (autocorrected) - `Timecop.scale` & `Timecop.travel` should be replaced with `travel` or `travel_to`. - Explicitly travelling again should be used instead of relying on time continuing to flow - `Timecop` should not appear anywhere
# Moreover, because `TimeHelpers` relies on Minitest teardown hooks, | ||
# `rails_helper` must be required (instead of `spec_helper`), or a | ||
# similar adapter layer must be in effect. |
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.
I do not understand this part of the comments. I think what is required is that #travel_back
is called in an after
block in the spec configuration (be it rails_helper or spec_helper or other).
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.
You're right. It's not that TimeHelpers need to be required from rails_helper, or rails_helper should be required.
Minitest teardown hooks will only run for Rails example groups, those where specific metadata is set (:model
, :controller
etc), manually in each spec, or with define_derived_metadata
.
This note should be changed accordingly.
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.
On a slightly different note, the RSpec maintainers plan to sunset setting this metadata automatically with define_derived_metadata
sometimes in the future, I think our users will either:
- define derived metadata on their own
- start setting metadata explicitly
We don't know for sure, so relying on explicitly set metadata to skip or proceed with this inspection is not a viable option.
Maybe rspec-rails should wrap TimeHelpers module with their own that would inject after { reset_time_helpers! }
? We could then write a cop that suggests using this module instead.
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.
I really like that Timecop has a safe mode. The equivalent would be that you can only call #travel
and #freeze_time
with a block, and the teardown / after block is not necessary.
That said, I can just disable this cop in projects where I prefer to use Timecop.
@bquorning We may add a separate cop that would enforce using only safe AS TimeHelpers methods variants. Honestly, I can’t say I fully understand the point of the safe mode really is. Is it to reset stubs after the example was run? To my best memory, the cleanup only happens to Rails example groups (those for models, controllers etc). If you include and use TestHelpers outside of a Rails example group, the time won’t travel back. Some discussion in rspec-rails. |
test "something" do
freeze_time do
# do something with frozen time
end
# do something with normal time
end Footnotes
|
I guess my question is: Does RSpec unconditionally call the |
This comment was marked as resolved.
This comment was marked as resolved.
Only in Rails example groups where the MinitestLifecycleAdapter is included. |
Is |
TimeHelpers are not included by default. |
Add Timecop cop
This PR is a revival of rubocop/rubocop-rails#38
All due credit for the implementation goes to @sambostock
Fixes rubocop/rubocop-rails#20
Style guide rubocop/rspec-style-guide#71
Changes from the original PR:
travel_back
with a block that appeared in Rails 6.1What
Why?
Rails projects already depend on ActiveSupport, which gives them most of the functionality Timecop provides.
While Timecop does provide some functionality TimeHelpers doesn't, the desired behaviour is better expressed by being explicit.
For instance, Timecop.scale should probably be replaced by explicitly calling travel or travel_to.
Disallowing Timecop in favour of TimeHelpers allows projects to remove Timecop as a dependency.
I might be misinterpreting this statement to my liking, please correct me if so. But from my perspective, it means "use what is built-in in Rails, and only replace its parts with what third-party provide when absolutely necessary".
Also, from my personal experience (from 7 years back) Timecop was contributing to some peculiar thread-related issues, suggesting that it's not thread-safe. I may be mistaken after all those years, so please take this note lightly.
Benchmark
A benchmark to compare the two, across 100,000 trials.
While TimeHelpers is certainly much slower, a difference of a few seconds across a 100,000 tests is not a meaningful penalty.
NOTE: this benchmark is 5 years old.
Before submitting the PR make sure the following are checked:
master
(if not - rebase it).CHANGELOG.md
if the new code introduces user-observable changes.bundle exec rake
) passes (be sure to run this locally, since it may produce updated documentation that you will need to commit).If you have created a new cop:
config/default.yml
.Enabled: pending
inconfig/default.yml
.VersionAdded: "<<next>>"
indefault/config.yml
.