Shared modules override example group methods if configured later
Created by: eugeneius
RSpec.describe do
let(:users) { [:first_user, :second_user] }
it do
expect(users.length).to eq(2)
end
end
module Fixtures
def users
[:a_user]
end
end
RSpec.configure do |config|
config.include Fixtures
end
# Failure/Error: expect(users.length).to eq(2)
#
# expected: 2
# got: 1
The users
method in the Fixtures
module is overriding the users
method in the example group. This used to work correctly, but started failing from 3.2.0 onwards. The problem is caused by the new singleton example group feature: when the example group is defined, the shared module isn't configured yet, so it isn't included. Right before each example runs, the shared module is included in the singleton example group, because at this point it has been added to the configuration.
Changing RSpec's configuration after example groups have already been defined may seem strange, but it can easily happen if you have multiple spec helpers, which rspec-rails
now generates by default: https://www.relishapp.com/rspec/rspec-rails/v/3-0/docs/upgrade#default-helper-files
I see two potential solutions here:
- Create the example group instance when the example is defined, not when it's run; this way the shared module configuration it uses is consistent with the example group itself. Alternatively, store the shared module configuration somehow when the example is defined, so it can be included correctly later. Both of these approaches seem like they could bloat memory usage a lot.
- Only include shared modules in the singleton example group if their metadata doesn't match the example group itself. If the metadata matches the example group, then it should have already been included when the example group was defined; if it wasn't, the shared module must have been added to the configuration afterwards, and in that case we don't want to include it.
I could probably figure out how to implement the second approach, but I wanted to sanity check it first, and make sure this behaviour is even intended to work - maybe changing the configuration after example groups have been defined shouldn't be supported at all.