FrozenError when adding a factory called :product
ksnyder opened this issue · comments
On Rails 5.2.1, and FactoryGirl 4.8.0 (factory_girl_rails same version), I copied an existing factory called :product_spec and renamed it :product.
After doing that, the specs won't run. I get this error on every spec file:
An error occurred while loading ./spec/models/user_spec.rb.
Failure/Error: require File.expand_path('../../config/environment', __FILE__)
FrozenError:
can't modify frozen Array
The contents of the factory don't matter -- if I completely empty the factory, I still get the error. If I rename the factory to :product1, the error goes away. Whether or not the class name is passed doesn't make a difference. It appears :product is some kind of reserved word in factory_girl?
Code that fails:
factory :product, class: Product do
#
end
No, product isn't a reserved word. I think you may be running into #247. Can you provide a backtrace, or any additional information? I haven't been able to reproduce this myself, which makes it difficult to debug.
Here's the backtrace:
Sorry for the font, but the included # and ` characters in the stacktrace seem to trigger Markdown...
An error occurred while loading ./spec/models/user_spec.rb.
Failure/Error: require File.expand_path('../../config/environment', __FILE__)
FrozenError:
can't modify frozen Array
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/actionpack-5.2.1/lib/action_dispatch/middleware/stack.rb:76:in `insert'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/actionpack-5.2.1/lib/action_dispatch/middleware/stack.rb:76:in `insert'
# ./config/initializers/cors.rb:8:in `<top (required)>'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:281:in `load'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:281:in `block in load'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:281:in `load'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/railties-5.2.1/lib/rails/engine.rb:657:in `block in load_config_initializer'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/notifications.rb:170:in `instrument'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/railties-5.2.1/lib/rails/engine.rb:656:in `load_config_initializer'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/railties-5.2.1/lib/rails/engine.rb:614:in `block (2 levels) in <class:Engine>'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/railties-5.2.1/lib/rails/engine.rb:613:in `each'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/railties-5.2.1/lib/rails/engine.rb:613:in `block in <class:Engine>'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/railties-5.2.1/lib/rails/initializable.rb:32:in `instance_exec'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/railties-5.2.1/lib/rails/initializable.rb:32:in `run'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/railties-5.2.1/lib/rails/initializable.rb:61:in `block in run_initializers'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/railties-5.2.1/lib/rails/initializable.rb:50:in `each'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/railties-5.2.1/lib/rails/initializable.rb:50:in `tsort_each_child'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/railties-5.2.1/lib/rails/initializable.rb:60:in `run_initializers'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/railties-5.2.1/lib/rails/application.rb:361:in `initialize!'
# ./config/environment.rb:5:in `<top (required)>'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `block in require'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
# ./spec/rails_helper.rb:3:in `<top (required)>'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `block in require'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
# ./spec/models/user_spec.rb:1:in `<top (required)>'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:281:in `load'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:281:in `block in load'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
# /Users/byofuel/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:281:in `load'
No examples found.
Yeah, this seems to be similar to #247. The error comes from calling insert on a frozen array here: https://github.com/rails/rails/blob/5-2-1/actionpack/lib/action_dispatch/middleware/stack.rb#L76. This error isn't pointing to anything obvious in factory_bot or factory_bot_rails. This issue on Rails also seems related: rails/rails#33745
Since there isn't anything obviously pointing to factory_bot, and there is some indication that it might have been fixed (see #247 (comment)) I'm going to close this issue for now. If you are able to share a sample app that reproduces the error, I would be happy to help debug. Thanks!
Actually I think I was able to reproduce this after all!
I wrote this invalid factory:
Factory.define do
factory :user
factory :user
end
When we run the test suite RSpec starts by loading every spec file. It goes something like this:
- RSpec loads
first_spec.rb
first_spec.rb
requiresrails_helper.rb
rails_helper.rb
requiresconfig/environment.rb
config/environment.rb
initializes the Rails application, which includes inserting all the middlewares, then freezing the middleware Stack- After the app initializes, factory_bot_rails loads the factory definitions
factory_bot_rails/lib/factory_bot_rails/railtie.rb
Lines 25 to 27 in 8f3076d
- Loading definitions fails with a
FactoryBot::DuplicateDefinitionError
- As a result of this failure
config/environment.rb
andrails_helper.rb
don't ever fully load (i.e. they don't appear in $LOADED_FEATURES) - RSpec rescues the error and reports it
https://github.com/rspec/rspec-core/blob/9d1d0d6aeb8dc87ff4e584cdcf9e8b1a234da2ae/lib/rspec/core/configuration.rb#L2035-L2037 - But RSpec doesn't give up, it continues trying to load the next spec ->
second_spec.rb
second_spec.rb
requiresrails_helper.rb
rails_helper.rb
requiresconfig/environment.rb
- 'config/environment.rb' tries to initializes the Rails application again, but it can't insert middleware because the stack is already frozen
- We get a
FrozenError
, which RSpec rescues and reports - RSpec continues on, and we likely see a whole bunch of
FrozenError
s
The FactoryBot::DuplicateDefinitionError
does get reported correctly, but I can see how this would be confusing, and how one might miss the FactoryBot::DuplicateDefinitionError
because it gets pushed out of sight by a bunch of FrozenError
s.
Actually, it seems like rspec/rspec-core#2568 addressed exactly this