-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
What Ruby, Rails and RSpec versions are you using?
Ruby version: 2.6.6
Rails version: 6.0.3.5
RSpec version: 3.10.1
Observed behaviour
We have dependabot and the recent upgrade failed some of our specs. Particularly specs that specifically test the method to_s
on an object. An example:
AR Object
class SomeActiveRecordObject < ApplicationRecord
validates :name, presence: true
delegate :to_s, to: :name
end
Spec
RSpec.describe SomeActiveRecordObject do
subject(:some_active_record_object) { described_class.new }
describe '#to_s' do
subject(:to_s) { some_active_record_object.to_s }
before { some_active_record_object.name = 'new name' }
it 'delegates to name' do
expect(some_active_record_object.to_s).to eq 'new name'
end
end
end
Expected behaviour
The expected behaviour is for the spec to pass seeing it's very simple. This spec fails with the new code because name
is blank in the beginning and is somehow being memoised already.
Can you provide an example app?
The above already shows the example. Further more, we already have an idea on what the bug is but not sure how to fix it.
This is the specific commit that breaks it: https://github.com/rspec/rspec-rails/pull/2461/files
More specifically this change:
def run_in_transaction?
use_transactional_tests && !self.class.uses_transaction?(self)
end
The issue is when the subject
is named to_s
(as in subject(:to_s) { something.to_s }
), uses_transaction
somehow uses the actual active record object - instead of the RSpec example.
This is the "offending line": https://github.com/rails/rails/blob/df41acdad93783dcac49f03036c3f34cb1c6c667/activerecord/lib/active_record/test_fixtures.rb#L96
def uses_transaction?(method)
@uses_transaction = [] unless defined?(@uses_transaction)
@uses_transaction.include?(method.to_s) # for some reason "method" here becomes the AR object - so it 'memoises' the value already even before you hit the before block
end
end
I have added an example spec to the existing spec for name collision - I think it's related there. Here is the sample:
Final note
You don't actually need to inherit from AR for this to happen - but you do need to have included include ActiveRecord::TestFixtures
since it's that method that is the problem. Not sure if it's an rspec-rails issue or a bug with active-record fixtures (or both!)