Description
What Ruby, Rails and RSpec versions are you using?
Ruby version: 3.3.3
Rails version: 7.1
RSpec version: 6.1.3 (vs working, 6.1.2)
Observed behaviour
The reset behaviour occurs in between the suite's config.around :each
(e.g. in spec_helper.rb
) and any context
/describe
block's before :each ...
(or more generally, before examples thereafter run). This breaks any tests which had current attributes set up in the config, upon which tests subsequently rely. This bug is the reason for ErwinM/acts_as_tenant#338.
Expected behaviour
We strongly suggest that the reset should happen either after all other "each"-style example hooks have concluded, or before any "each"-style example hooks start. It should never happen invisibly in between "each"-style hooks.
The inclusion of ActiveSupport::CurrentAttributes::TestHelper
within RSpec::Rails::RailsExampleGroup
is not IMHO all that wise, because it can only work if the implementation therein has a particular defined way of doing something that's directly compatible with any other callback chains and callback ordering in the wider scope of tests. That's simply not the case, as we can see. The ActiveSupport implementation seems to be over-zealous, resetting both before and after examples run (from RSpec's perspective):
def before_setup
ActiveSupport::CurrentAttributes.reset_all
super
end
def after_teardown
super
ActiveSupport::CurrentAttributes.reset_all
end
...and it seems to me that just the after_teardown
callback is all you actually need to achieve the functionality that #2752 desired, without breaking existing tests; you could simply do that directly inside RailsExampleGroup
in place of include ActiveSupport::CurrentAttributes::TestHelper
. This would get around a lot of issues I suspect, but it is clearly still not perfect - you are not controlling callback order here - there's still an edge case chance that someone's spec_helper.rb
might have its own after-example code in a config.around :each
or config.after :each
which expects to do things with whatever is expected to be still inside CurrentAttributes
, other than just resetting. That's why we recommend making sure somehow that this action is either done first in the callback chain (or at least before any "user defined" callbacks run), or last, after any "user defined" callbacks, per example.
Can you provide an example reproduction?
Yes. A tiny stripped down almost-Rails application with README.md
containing additional information and a replication test case is included.