diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..2559e39 --- /dev/null +++ b/.rspec @@ -0,0 +1,3 @@ +--color +--format progress +--require spec_helper diff --git a/Rakefile b/Rakefile index dfe61c2..6b5fb85 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,6 @@ require 'bundler/setup' require 'cucumber/rake/task' +require 'rspec/core/rake_task' Bundler::GemHelper.install_tasks name: 'factory_bot_rails' @@ -8,12 +9,14 @@ Cucumber::Rake::Task.new(:cucumber) do |t| t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'progress')] end +RSpec::Core::RakeTask.new(:spec) + require 'appraisal' desc 'Run the test suite' task :default do |t| if ENV['BUNDLE_GEMFILE'] =~ /gemfiles/ - exec 'rake cucumber' + exec 'rake spec && rake cucumber' else Rake::Task['appraise'].execute end diff --git a/lib/factory_bot_rails/definition_file_paths.rb b/lib/factory_bot_rails/definition_file_paths.rb new file mode 100644 index 0000000..dd0178b --- /dev/null +++ b/lib/factory_bot_rails/definition_file_paths.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module FactoryBotRails + class DefinitionFilePaths + attr_reader :files, :directories + + def initialize(definition_file_paths) + @files = [] + @directories = {} + + definition_file_paths.each do |path| + @files << "#{path}.rb" + @directories[path.to_s] = [:rb] + end + end + end +end diff --git a/lib/factory_bot_rails/railtie.rb b/lib/factory_bot_rails/railtie.rb index f7af2b0..bd39882 100644 --- a/lib/factory_bot_rails/railtie.rb +++ b/lib/factory_bot_rails/railtie.rb @@ -1,28 +1,31 @@ -require 'factory_bot' -require 'factory_bot_rails/generator' -require 'rails' +# frozen_string_literal: true -module FactoryBot +require "factory_bot" +require "factory_bot_rails/generator" +require "factory_bot_rails/reloader" +require "rails" + +module FactoryBotRails class Railtie < Rails::Railtie initializer "factory_bot.set_fixture_replacement" do - FactoryBotRails::Generator.new(config).run + Generator.new(config).run end initializer "factory_bot.set_factory_paths" do FactoryBot.definition_file_paths = [ - Rails.root.join('factories'), - Rails.root.join('test', 'factories'), - Rails.root.join('spec', 'factories') + Rails.root.join("factories"), + Rails.root.join("test", "factories"), + Rails.root.join("spec", "factories"), ] end + initializer "factory_bot.register_reloader" do |app| + Reloader.new(app, config).run + end + config.after_initialize do FactoryBot.find_definitions - - if defined?(Spring) - Spring.after_fork { FactoryBot.reload } - end end end end diff --git a/lib/factory_bot_rails/reloader.rb b/lib/factory_bot_rails/reloader.rb new file mode 100644 index 0000000..329ac26 --- /dev/null +++ b/lib/factory_bot_rails/reloader.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require "factory_bot_rails/definition_file_paths" + +module FactoryBotRails + class Reloader + def initialize(app, config) + @app = app + @config = config + end + + def run + register_reloader(build_reloader) + end + + private + + attr_reader :app, :config + + def build_reloader + paths = DefinitionFilePaths.new(FactoryBot.definition_file_paths) + + reloader_class.new(paths.files, paths.directories) do + FactoryBot.reload + end + end + + def reloader_class + app.config.file_watcher + end + + def register_reloader(reloader) + config.to_prepare do + reloader.execute_if_updated + end + + app.reloaders << reloader + end + end +end diff --git a/lib/generators/factory_bot/model/model_generator.rb b/lib/generators/factory_bot/model/model_generator.rb index d5a49eb..4db0e21 100644 --- a/lib/generators/factory_bot/model/model_generator.rb +++ b/lib/generators/factory_bot/model/model_generator.rb @@ -91,7 +91,7 @@ RUBY end def generators - config = FactoryBot::Railtie.config + config = FactoryBotRails::Railtie.config config.respond_to?(:app_generators) ? config.app_generators : config.generators end end diff --git a/spec/factory_bot_rails/definition_file_paths_spec.rb b/spec/factory_bot_rails/definition_file_paths_spec.rb new file mode 100644 index 0000000..68ccad6 --- /dev/null +++ b/spec/factory_bot_rails/definition_file_paths_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +describe FactoryBotRails::DefinitionFilePaths do + describe "#files" do + it "returns a list of definition files" do + definition_file_paths = ["definition_path", "another_definition_path"] + + files = described_class.new(definition_file_paths).files + + expect(files).to eq ["definition_path.rb", "another_definition_path.rb"] + end + end + + describe "#directories" do + it "returns a hash of definition directories" do + definition_file_paths = ["definition_path", "another_definition_path"] + + directories = described_class.new(definition_file_paths).directories + + expect(directories).to eq( + "definition_path" => [:rb], + "another_definition_path" => [:rb], + ) + end + + it "converts Pathname objects to strings" do + definition_file_paths = [Pathname.new("definition_path")] + + directories = described_class.new(definition_file_paths).directories + + expect(directories).to eq("definition_path" => [:rb]) + end + end +end diff --git a/spec/factory_bot_rails/railtie_spec.rb b/spec/factory_bot_rails/railtie_spec.rb new file mode 100644 index 0000000..b03e680 --- /dev/null +++ b/spec/factory_bot_rails/railtie_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +describe FactoryBotRails::Railtie do + describe "application reloading" do + context "when a definition file has been updated" do + it "reloads the factory definitions" do + allow(FactoryBot).to receive(:reload) + + touch("factories.rb") + reload_rails! + + expect(FactoryBot).to have_received(:reload) + end + end + + context "when a file in a definition directory has been updated" do + it "reloads the factory definitions" do + allow(FactoryBot).to receive(:reload) + + touch("factories/definitions.rb") + reload_rails! + + expect(FactoryBot).to have_received(:reload) + end + end + + context "when the factory definitions have NOT been updated" do + it "does NOT reload the factory definitions" do + allow(FactoryBot).to receive(:reload) + + reload_rails! + + expect(FactoryBot).not_to have_received(:reload) + end + end + + def touch(file) + FileUtils.touch(Rails.root.join(file)) + end + + def reload_rails! + if defined? ActiveSupport::Reloader + Rails.application.reloader.reload! + else + # For Rails 4 + ActionDispatch::Reloader.cleanup! + ActionDispatch::Reloader.prepare! + end + + wait_for_rails_to_reload + end + + def wait_for_rails_to_reload + sleep 0.01 + end + end +end diff --git a/spec/fake_app.rb b/spec/fake_app.rb new file mode 100644 index 0000000..37e7b2a --- /dev/null +++ b/spec/fake_app.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Dummy + class Application < Rails::Application + config.eager_load = false + config.root = "spec/fixtures" + end +end + +Rails.logger = Logger.new("/dev/null") + +Rails.application.initialize! diff --git a/spec/fixtures/factories.rb b/spec/fixtures/factories.rb new file mode 100644 index 0000000..82e878d --- /dev/null +++ b/spec/fixtures/factories.rb @@ -0,0 +1 @@ +# Rails.root.join('factories.rb') diff --git a/spec/fixtures/factories/definitions.rb b/spec/fixtures/factories/definitions.rb new file mode 100644 index 0000000..37149d4 --- /dev/null +++ b/spec/fixtures/factories/definitions.rb @@ -0,0 +1 @@ +# Rails.root.join('factories', 'definitions.rb') diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..5cbcde8 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +ENV["RAILS_ENV"] = "test" + +require "factory_bot_rails" +require "fake_app" + +RSpec.configure do |config| + config.run_all_when_everything_filtered = true + config.filter_run :focus + config.order = "random" +end