Reputation: 2118
For my first Ruby on Rails engine - named "glossary" - I wish to implement Rspec, ShouldaMatchers, FactoryBot as test suite. Things look good, but FactoryBot keeps claiming that factories are not registered:
Failures:
1) Glossary::User
Failure/Error: subject {FactoryBot.build(:user)}
ArgumentError:
Factory not registered: user
In the development process,
rails generate model user first_name last_name user_name
created the following files:
which looks good.
rails_helper.rb contains the following:
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../dummy/config/environment.rb', __FILE__)
require 'spec_helper'
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
require 'shoulda/matchers'
require 'factory_bot_rails'
FactoryBot.definition_file_paths << File.expand_path('../spec/factories', __FILE__)
---
# Fred 2018-07-29: added to engine configuration
Shoulda::Matchers.configure do |config|
config.integrate do |with|
# Choose a test framework:
with.test_framework :rspec
# Choose one or more libraries:
with.library :rails
end
end
# spec/support/factory_bot.rb
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
lib/glossary/engine.rb contains the following:
module Glossary
class Engine < ::Rails::Engine
isolate_namespace Glossary
# Fred 2018-07-29: added to engine configuration
config.generators do |g|
g.test_framework :rspec
g.fixture_replacement :factory_bot
g.factory_bot dir: 'spec/factories'
end
end
end
FactoryBot generated this spec/factories/glossary_users.rb file:
FactoryBot.define do
factory :glossary_user, class: 'Glossary::User' do
first_name "MyString"
last_name "MyString"
user_name "MyString"
end
end
which I refer to in the spec/models/glossary/user_spec.rb file:
require 'rails_helper'
module Glossary
RSpec.describe User, type: :model do
describe 'Validations'
subject {FactoryBot.build(:user)}
it { should validate_presence_of(:user_name) }
end
end
Nevertheless, issuing the following command in the rails console does not return the expected path, and factories remain not found:
Fred:glossary$ rails console
Loading development environment (Rails 5.2.0)
irb(main):001:0> FactoryBot.find_definitions
=> ["/var/www/glossary/spec/dummy/factories", "/var/www/glossary/spec/dummy/test/factories", "/var/www/glossary/spec/dummy/spec/factories"]
irb(main):002:0>
Did I miss something in the setup or configuration?
Thanks for your help!
Upvotes: 1
Views: 4129
Reputation: 2343
This will make factories that you define in your engine available to the apps that depend on your engine.
In your lib/my_engine/engine.rb
:
module MyEngine
class Engine < ::Rails::Engine
initializer :load_factories, after: 'factory_bot.set_factory_paths' do
if defined?(FactoryBot) && defined?(Faker) && !Rails.env.production?
FactoryBot.definition_file_paths.prepend(
File.join(MyEngine.root, 'spec', 'factories')
)
end
end
end
end
I like to protect it with a conditional to ensure it only runs under the appropriate conditions. You can find other variations on this in the FactoryBot codebase.
Upvotes: 0
Reputation: 35
I had this similar problem, I rearranged my code as
# rails_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
# for factory bot
require 'factory_bot_rails'
And my test.rb as
# test.rb
config.eager_load = false
# some config
config.factory_bot.definition_file_paths += ["<my path"]
Edit 1: Explanation
So FactoryBot scans the directories present in FactoryBot.definition_file_paths
and registers all the factories by invoking FactoryBot.find_definitions
The FactoryBot.find_definitions
invocation occurs when we
require 'factory_bot_rails`
Hence the order of statements inside rails_helper.rb
matters
Edit 2: The above solution disregards the typo in factory usage as pointed out by others
Upvotes: 1
Reputation: 44380
The Factory have name glossary_user
and should used as FactoryBot.build(:glossary_user)
Upvotes: 0