-
-
Notifications
You must be signed in to change notification settings - Fork 529
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce
suspenders:factory_bot
generator
Maintains functionally with the [existing generator][] while adding support for the [default Rails test suite]. With this change, the generator can be invoked on a Rails application that use RSpec and the default Rails test suite. Adds generator which adds a test to lint all Factories in an effort to improve developer experience. [existing generator]: https://github.com/thoughtbot/suspenders/blob/main/lib/suspenders/generators/factories_generator.rb [default Rails test suite]: https://guides.rubyonrails.org/testing.html
- Loading branch information
1 parent
44f783e
commit ed5e4a6
Showing
6 changed files
with
313 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
module Suspenders | ||
module Generators | ||
class FactoryBotGenerator < Rails::Generators::Base | ||
source_root File.expand_path("../../templates/factory_bot", __FILE__) | ||
|
||
def add_factory_bot | ||
gem_group :development, :test do | ||
gem "factory_bot_rails" | ||
end | ||
|
||
Bundler.with_unbundled_env { run "bundle install" } | ||
end | ||
|
||
def set_up_factory_bot | ||
if default_test_helper_present? | ||
insert_into_file Rails.root.join("test/test_helper.rb"), after: "class TestCase" do | ||
"\n include FactoryBot::Syntax::Methods" | ||
end | ||
elsif rspec_test_helper_present? | ||
copy_file "factory_bot_rspec.rb", "spec/support/factory_bot.rb" | ||
insert_into_file Rails.root.join("spec/rails_helper.rb") do | ||
%(Dir[Rails.root.join("spec/support/**/*.rb")].sort.each { |file| require file }) | ||
end | ||
end | ||
end | ||
|
||
def generate_empty_factories_file | ||
if default_test_suite? | ||
copy_file "factories.rb", "test/factories.rb" | ||
elsif rspec_test_suite? | ||
copy_file "factories.rb", "spec/factories.rb" | ||
end | ||
end | ||
|
||
def provide_dev_prime_task | ||
copy_file "dev.rake", "lib/tasks/dev.rake" | ||
end | ||
|
||
def remove_fixture_definitions | ||
if default_test_helper_present? | ||
comment_lines "test/test_helper.rb", /fixtures :all/ | ||
end | ||
end | ||
|
||
def create_linting_test | ||
if default_test_suite? | ||
copy_file "factories_test.rb", "test/factory_bots/factories_test.rb" | ||
end | ||
end | ||
|
||
private | ||
|
||
def default_test_suite? | ||
File.exist? Rails.root.join("test") | ||
end | ||
|
||
def rspec_test_suite? | ||
File.exist? Rails.root.join("spec") | ||
end | ||
|
||
def default_test_helper_present? | ||
File.exist? Rails.root.join("test/test_helper.rb") | ||
end | ||
|
||
def rspec_test_helper_present? | ||
File.exist? Rails.root.join("spec/rails_helper.rb") | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
if Rails.env.development? || Rails.env.test? | ||
require "factory_bot" | ||
|
||
namespace :dev do | ||
desc "Sample data for local development environment" | ||
task prime: "db:setup" do | ||
include FactoryBot::Syntax::Methods | ||
|
||
# create(:user, email: "[email protected]", password: "password") | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
FactoryBot.define do | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
require "test_helper" | ||
|
||
class FactoryBotsTest < ActiveSupport::TestCase | ||
class FactoryLintingTest < FactoryBotsTest | ||
test "linting of factories" do | ||
FactoryBot.lint traits: true | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
FactoryBot.use_parent_strategy = true | ||
|
||
RSpec.configure do |config| | ||
config.include FactoryBot::Syntax::Methods | ||
end |
215 changes: 215 additions & 0 deletions
215
test/generators/suspenders/factory_bot_generator_test.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
require "test_helper" | ||
require "generators/suspenders/factory_bot_generator" | ||
|
||
module Suspenders | ||
module Generators | ||
class FactoryBotGenerator::DefaultTest < Rails::Generators::TestCase | ||
include Suspenders::TestHelpers | ||
|
||
tests Suspenders::Generators::FactoryBotGenerator | ||
destination Rails.root | ||
setup :prepare_destination | ||
teardown :restore_destination | ||
|
||
test "generator runs without errors" do | ||
assert_nothing_raised do | ||
run_generator | ||
end | ||
end | ||
|
||
test "installs gem with Bundler" do | ||
Bundler.stubs(:with_unbundled_env).yields | ||
generator.expects(:run).with("bundle install").once | ||
|
||
capture(:stdout) do | ||
generator.add_factory_bot | ||
end | ||
end | ||
|
||
test "removes fixture definitions" do | ||
File.open(app_root("test/test_helper.rb"), "w") { _1.write test_helper } | ||
|
||
run_generator | ||
|
||
assert_file app_root("test/test_helper.rb") do |file| | ||
assert_match(/# fixtures :all/, file) | ||
end | ||
end | ||
|
||
test "adds gem to Gemfile" do | ||
run_generator | ||
|
||
assert_file app_root("Gemfile") do |file| | ||
assert_match(/group :development, :test do\n gem "factory_bot_rails"\nend/, file) | ||
end | ||
end | ||
|
||
test "includes syntax methods" do | ||
File.open(app_root("test/test_helper.rb"), "w") { _1.write test_helper } | ||
|
||
run_generator | ||
|
||
assert_file app_root("test/test_helper.rb") do |file| | ||
assert_match(/class TestCase\n include FactoryBot::Syntax::Methods/, file) | ||
end | ||
end | ||
|
||
test "creates definition file" do | ||
run_generator | ||
|
||
assert_file app_root("test/factories.rb") do |file| | ||
assert_match definition_file, file | ||
end | ||
end | ||
|
||
test "creates linting test" do | ||
run_generator | ||
|
||
assert_file app_root("test/factory_bots/factories_test.rb") do |file| | ||
assert_match factories_test, file | ||
end | ||
end | ||
|
||
test "creates dev prime task" do | ||
run_generator | ||
|
||
assert_file app_root("lib/tasks/dev.rake") do |file| | ||
assert_match dev_rake, file | ||
end | ||
end | ||
|
||
private | ||
|
||
def prepare_destination | ||
mkdir "test" | ||
touch "Gemfile" | ||
end | ||
|
||
def restore_destination | ||
remove_dir_if_exists "test" | ||
remove_dir_if_exists "spec" | ||
remove_file_if_exists "Gemfile" | ||
remove_dir_if_exists "lib/tasks" | ||
end | ||
|
||
def test_helper | ||
<<-RUBY | ||
ENV["RAILS_ENV"] ||= "test" | ||
require_relative "../config/environment" | ||
require "rails/test_help" | ||
module ActiveSupport | ||
class TestCase | ||
# Run tests in parallel with specified workers | ||
parallelize(workers: :number_of_processors) | ||
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. | ||
fixtures :all | ||
# Add more helper methods to be used by all tests here... | ||
end | ||
end | ||
RUBY | ||
end | ||
|
||
def factories_test | ||
<<~RUBY | ||
require "test_helper" | ||
class FactoryBotsTest < ActiveSupport::TestCase | ||
class FactoryLintingTest < FactoryBotsTest | ||
test "linting of factories" do | ||
FactoryBot.lint traits: true | ||
end | ||
end | ||
end | ||
RUBY | ||
end | ||
|
||
def definition_file | ||
<<~RUBY | ||
FactoryBot.define do | ||
end | ||
RUBY | ||
end | ||
|
||
def dev_rake | ||
<<~RUBY | ||
if Rails.env.development? || Rails.env.test? | ||
require "factory_bot" | ||
namespace :dev do | ||
desc "Sample data for local development environment" | ||
task prime: "db:setup" do | ||
include FactoryBot::Syntax::Methods | ||
# create(:user, email: "[email protected]", password: "password") | ||
end | ||
end | ||
end | ||
RUBY | ||
end | ||
end | ||
|
||
class FactoryBotGenerator::RSpecTest < Rails::Generators::TestCase | ||
include Suspenders::TestHelpers | ||
|
||
tests Suspenders::Generators::FactoryBotGenerator | ||
destination Rails.root | ||
setup :prepare_destination | ||
teardown :restore_destination | ||
|
||
test "includes syntax methods" do | ||
touch("spec/rails_helper.rb") | ||
|
||
run_generator | ||
|
||
assert_file app_root("spec/support/factory_bot.rb") do |file| | ||
assert_match factory_bot_config, file | ||
end | ||
assert_file app_root("spec/rails_helper.rb") do |file| | ||
assert_match(/Dir\[Rails\.root\.join\("spec\/support\/\*\*\/\*\.rb"\)\]\.sort\.each { \|file\| require file }/, file) | ||
end | ||
end | ||
|
||
test "creates definition file" do | ||
run_generator | ||
|
||
assert_file app_root("spec/factories.rb") do |file| | ||
assert_match definition_file, file | ||
end | ||
end | ||
|
||
private | ||
|
||
def prepare_destination | ||
mkdir "spec" | ||
touch "Gemfile" | ||
end | ||
|
||
def restore_destination | ||
remove_dir_if_exists "test" | ||
remove_dir_if_exists "spec" | ||
remove_file_if_exists "Gemfile" | ||
remove_dir_if_exists "lib/tasks" | ||
end | ||
|
||
def factory_bot_config | ||
<<~RUBY | ||
FactoryBot.use_parent_strategy = true | ||
RSpec.configure do |config| | ||
config.include FactoryBot::Syntax::Methods | ||
end | ||
RUBY | ||
end | ||
|
||
def definition_file | ||
<<~RUBY | ||
FactoryBot.define do | ||
end | ||
RUBY | ||
end | ||
end | ||
end | ||
end |