Factory not registered: "credit_card"
vassalloandrea opened this issue · comments
I'm using Solidus to build an e-commerce.
Updating factory_bot_rails
from the version 4.11.1
to the latest 5.0.2
something broke.
Running the test locally, RSpec returns this error:
KeyError:
Factory not registered: "credit_card"
In this case, I included the credit_card
factory from Solidus and overrode it adding a cc_type.
My override: spec/factories/credit_card_factory.rb
# frozen_string_literal: true
require 'spree/testing_support/factories/credit_card_factory'
FactoryBot.modify do
factory :credit_card, class: Spree::CreditCard do
cc_type { 'Visa' }
end
end
Solidus factory: here the link
# frozen_string_literal: true
FactoryBot.define do
factory :credit_card, class: 'Spree::CreditCard' do
verification_value { 123 }
month { 12 }
year { 1.year.from_now.year }
number { '4111111111111111' }
name { 'Spree Commerce' }
association(:payment_method, factory: :credit_card_payment_method)
association(:address)
trait :failing do
number { "0000000000000000" }
end
end
end
I tried to figure out without success.
For now, I blocked the version on the project to factory_bot_rails
4.11.1
.
+1
Same situation with solidus 2.9.1 and factory_bot_rails 5.0.2
@vassalloandrea I think it's a "chicken and egg" problem. I fixed the problem by moving out the file where I use FactoryBot.modify
from spec/factories
into another folder which is not autorequired from factory_bot, like spec/modified_spree_factories
, then I manually require all files inside this new folder:
Inside rails_helper.rb
require 'spree/testing_support/factories'
Dir[Rails.root.join('spec', 'modified_spree_factories', '**', '*.rb')].sort.each { |file| require file }
Hope it helps!
This has to do with FactoryBot.reload
not playing well with require
s in the definitions. FactoryBot.reload
wipes out all of the factory definitions (including the spree definitions), and then reloads any definition files it knows about using load
. If the spree definitions have already been require
d, require
is a no-op the second time around.
This has always been a problem when using spring, since spring triggers a FactoryBot.reload
in its forked process. It worked in 4.11 without spring because the definitions were only ever loaded once (unless you manually called FactoryBot.reload
). This broke in 5.0 because there was a bug causing us to reload the definitions twice. We fixed the double reloading in 1e55d45, so if you upgrade to >= 5.1.1 the problem should go away (assuming you don't use spring).
It would be nice if we could get this use case working with spring, but I think that would require changes on the solidus side. We have an official way of sharing factories in the README, but solidus is not sharing them like that. You could add something like:
config.factory_bot.definition_file_paths.unshift(
Gem::Specification.find_by_name("solidus_core").gem_dir +
"/lib/spree/testing_support/factories/credit_card_factory"
)
to your application config to let factory_bot handle reloading the definitions as necessary, but unfortunately you can't do that with the whole "/lib/spree/testing_support/factories" directory because some of the factories there require
other factories. You would have to configure them in whatever order solidus expects.
Another approach would be to set config.factory_bot.definition_file_paths = []
so factory_bot_rails doesn't handle any of the definition loading at all and then manually require the files you want in the order you want them. (This is effectively what @delphaber did by moving things into a directory factory_bot_rails doesn't know about.)
I will probably close this issue, since factory_bot_rails is back to the old behavior, and we do have a documented way of sharing factories.
Thank you very much for the explanation @composerinteralia !
@composerinteralia , I'm getting the Factory not registered
error in Rails 6, and I'm not using Solidus. I'm not using rspec, so it's just the default minitest that comes with Rails.
The factory is pretty simple and defined in test/factories.rb:
FactoryBot.define do
sequence :email do |n|
"user#{n}@example.com"
end
factory :user do
email
password { "password123" }
end
end
Should I create a separate issue?
If I add FactoryBot.reload
in test_helper.rb, I don't get the error:
class ActiveSupport::TestCase
[... redacted ...]
FactoryBot.reload
include FactoryBot::Syntax::Methods
end
@mikong If you don't have solidus anywhere in your Gemfile.lock then this is a separate issue. I don't see anything obviously wrong in your code. Could you provide a sample application that reproduces the problem?
@composerinteralia The error isn't happening anymore in my application. I tried to replicate the error in a branch just after I added factory_bot_rails but it's also no longer happening. If I reproduce the error next time, I'll open a new issue with a link to a sample application. Thanks.
Sounds good. Thanks!
I am going to close this issue for now for the reasons mentioned in #341 (comment).
This is still an issue in Rails 6, I had to add
FactoryBot.reload
after appending a new route in definition_file_paths
array in my rails_helper.rb
that solved the issue for me
Same here, rails 6, sometimes factories can't be found.
FactoryBot.reload suggestion solves the issue
Ran into this issue just now. In implementing the above, I was able to get my factories to work in the console, but unable to run my specs. I discovered that adding config.include FactoryBot::Syntax::Methods
to my rails_helper.rb
solved the issue for me and my specs now run! I found the suggestion in this thread.
This is still an issue in Rails 6, I had to add
FactoryBot.reload
after appending a new route indefinition_file_paths
array in myrails_helper.rb
that solved the issue for me
Same here, rails 6, Factory not registered: "user"
FactoryBot.reload
suggestion solves the issue
Thanks for supporting. It's worked for me <3
Was stuck on the same issue for a while for rails 6.1.7.3
and factory_bot_rails 6.2.0
(not using Spring or Solidus). Turns out, I had the /factories
folder in the wrong location, relative to the paths that FactoryBot was searching for loading. I did not need the explicit FactoryBot.reload
code addition in rails_helper.rb
or spec_helper.rb
.
If you spin up rails c
for your project and run FactoryBot.reload
, you'll see the array of file paths that FactoryBot is looking for to find your factories. Mine was nested one level above all the paths, and I just had to move it so it complied with one of them and still made sense for my project structure.