Skip to content

Commit d423176

Browse files
committed
Add Railtie, RSpec/Minitest auto-generation, install generator, and README rewrite
- Add FixtureBot::Rails.generate with auto-detection of fixtures file and output dir - Add Railtie with config.fixturebot namespace and fixturebot:generate rake task - Add require "fixturebot/rspec" (before :suite hook) and "fixturebot/minitest" (require-time) - Add rails generate fixturebot:install for scaffolding - Add spec for FixtureBot::Rails.generate - Add spec for explicit nil shadowing generators - Rewrite README with fixtures-vs-factories motivation, Rails setup docs, and clearer generator examples
1 parent 40e4c6b commit d423176

File tree

9 files changed

+381
-140
lines changed

9 files changed

+381
-140
lines changed

README.md

Lines changed: 133 additions & 140 deletions
Large diffs are not rendered by default.

lib/fixturebot/minitest.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# frozen_string_literal: true
2+
3+
require "fixturebot/rails"
4+
5+
FixtureBot::Rails.generate

lib/fixturebot/rails.rb

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,53 @@
33
require "fixturebot"
44
require_relative "rails/schema_loader"
55
require_relative "rails/cli"
6+
require_relative "rails/railtie" if defined?(::Rails::Railtie)
7+
8+
module FixtureBot
9+
module Rails
10+
def self.generate(fixtures_file: nil, output_dir: nil)
11+
fixtures_file = resolve_fixtures_file(fixtures_file)
12+
return unless fixtures_file && File.exist?(fixtures_file)
13+
14+
output_dir = resolve_output_dir(output_dir, fixtures_file)
15+
16+
schema = SchemaLoader.load
17+
fixture_set = FixtureBot.define_from_file(schema, fixtures_file)
18+
YamlDumper.new(fixture_set).dump(output_dir)
19+
end
20+
21+
def self.resolve_fixtures_file(explicit)
22+
return explicit if explicit
23+
24+
if defined?(::Rails::Railtie) && ::Rails.application&.config&.respond_to?(:fixturebot)
25+
configured = ::Rails.application.config.fixturebot.fixtures_file
26+
return configured if configured
27+
end
28+
29+
detect_fixtures_file
30+
end
31+
private_class_method :resolve_fixtures_file
32+
33+
def self.resolve_output_dir(explicit, fixtures_file)
34+
return explicit if explicit
35+
36+
if defined?(::Rails::Railtie) && ::Rails.application&.config&.respond_to?(:fixturebot)
37+
configured = ::Rails.application.config.fixturebot.output_dir
38+
return configured if configured
39+
end
40+
41+
detect_output_dir(fixtures_file)
42+
end
43+
private_class_method :resolve_output_dir
44+
45+
def self.detect_fixtures_file
46+
%w[test/fixtures.rb spec/fixtures.rb].find { |f| File.exist?(f) }
47+
end
48+
private_class_method :detect_fixtures_file
49+
50+
def self.detect_output_dir(fixtures_file)
51+
fixtures_file.sub(/\.rb\z/, "")
52+
end
53+
private_class_method :detect_output_dir
54+
end
55+
end

lib/fixturebot/rails/railtie.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# frozen_string_literal: true
2+
3+
module FixtureBot
4+
module Rails
5+
class Railtie < ::Rails::Railtie
6+
config.fixturebot = ActiveSupport::OrderedOptions.new
7+
8+
rake_tasks do
9+
namespace :fixturebot do
10+
desc "Generate YAML fixture files from FixtureBot DSL"
11+
task generate: :environment do
12+
FixtureBot::Rails.generate
13+
end
14+
end
15+
end
16+
end
17+
end
18+
end

lib/fixturebot/rspec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# frozen_string_literal: true
2+
3+
require "fixturebot/rails"
4+
5+
RSpec.configure do |config|
6+
config.before(:suite) do
7+
FixtureBot::Rails.generate
8+
end
9+
end
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# frozen_string_literal: true
2+
3+
require "rails/generators"
4+
5+
module Fixturebot
6+
class InstallGenerator < ::Rails::Generators::Base
7+
source_root File.expand_path("templates", __dir__)
8+
9+
desc "Set up FixtureBot in your Rails application"
10+
11+
def create_fixtures_file
12+
if rspec?
13+
template "fixtures.rb.tt", "spec/fixtures.rb"
14+
else
15+
template "fixtures.rb.tt", "test/fixtures.rb"
16+
end
17+
end
18+
19+
def inject_require_into_helper
20+
if rspec?
21+
inject_into_file "spec/rails_helper.rb",
22+
"require \"fixturebot/rspec\"\n",
23+
after: "require 'rspec/rails'\n"
24+
else
25+
inject_into_file "test/test_helper.rb",
26+
"require \"fixturebot/minitest\"\n",
27+
after: "require \"rails/test_help\"\n"
28+
end
29+
end
30+
31+
private
32+
33+
def rspec?
34+
File.directory?(File.join(destination_root, "spec"))
35+
end
36+
end
37+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FixtureBot.define do
2+
# Define your fixtures here. Example:
3+
#
4+
# user :alice do
5+
# name "Alice"
6+
# email "alice@example.com"
7+
# end
8+
#
9+
# user :bob do
10+
# name "Bob"
11+
# end
12+
end
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# frozen_string_literal: true
2+
3+
require "fixturebot/rails"
4+
require "tmpdir"
5+
6+
RSpec.describe FixtureBot::Rails, ".generate" do
7+
before do
8+
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
9+
10+
ActiveRecord::Schema.define(version: 2024_01_01_000000) do
11+
create_table "users", force: :cascade do |t|
12+
t.string "name"
13+
t.string "email"
14+
t.timestamps
15+
end
16+
17+
create_table "posts", force: :cascade do |t|
18+
t.string "title"
19+
t.text "body"
20+
t.integer "author_id"
21+
t.timestamps
22+
end
23+
24+
add_foreign_key "posts", "users", column: "author_id"
25+
end
26+
end
27+
28+
after do
29+
ActiveRecord::Base.connection_pool.disconnect!
30+
end
31+
32+
it "generates YAML fixture files from a DSL file" do
33+
Dir.mktmpdir do |tmpdir|
34+
fixtures_file = File.join(tmpdir, "fixtures.rb")
35+
output_dir = File.join(tmpdir, "fixtures")
36+
37+
File.write(fixtures_file, <<~RUBY)
38+
FixtureBot.define do
39+
user :alice do
40+
name "Alice"
41+
email "alice@example.com"
42+
end
43+
44+
user :bob do
45+
name "Bob"
46+
email "bob@example.com"
47+
end
48+
49+
post :hello do
50+
title "Hello World"
51+
body "First post"
52+
author :alice
53+
end
54+
end
55+
RUBY
56+
57+
described_class.generate(fixtures_file: fixtures_file, output_dir: output_dir)
58+
59+
users_yaml = YAML.load_file(File.join(output_dir, "users.yml"))
60+
expect(users_yaml.keys).to contain_exactly("alice", "bob")
61+
expect(users_yaml["alice"]["name"]).to eq("Alice")
62+
expect(users_yaml["alice"]["email"]).to eq("alice@example.com")
63+
expect(users_yaml["bob"]["name"]).to eq("Bob")
64+
65+
posts_yaml = YAML.load_file(File.join(output_dir, "posts.yml"))
66+
expect(posts_yaml.keys).to contain_exactly("hello")
67+
expect(posts_yaml["hello"]["title"]).to eq("Hello World")
68+
end
69+
end
70+
71+
it "skips empty tables" do
72+
Dir.mktmpdir do |tmpdir|
73+
fixtures_file = File.join(tmpdir, "fixtures.rb")
74+
output_dir = File.join(tmpdir, "fixtures")
75+
76+
File.write(fixtures_file, <<~RUBY)
77+
FixtureBot.define do
78+
user :alice do
79+
name "Alice"
80+
email "alice@example.com"
81+
end
82+
end
83+
RUBY
84+
85+
described_class.generate(fixtures_file: fixtures_file, output_dir: output_dir)
86+
87+
expect(File.exist?(File.join(output_dir, "users.yml"))).to be true
88+
expect(File.exist?(File.join(output_dir, "posts.yml"))).to be false
89+
end
90+
end
91+
92+
it "returns early when fixtures file does not exist" do
93+
Dir.mktmpdir do |tmpdir|
94+
output_dir = File.join(tmpdir, "fixtures")
95+
96+
described_class.generate(
97+
fixtures_file: File.join(tmpdir, "nonexistent.rb"),
98+
output_dir: output_dir
99+
)
100+
101+
expect(Dir.exist?(output_dir)).to be false
102+
end
103+
end
104+
end

spec/fixturebot_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,19 @@
121121
expect(result.tables[:users][:admin][:email]).to eq("brad@blog.test")
122122
end
123123

124+
it "preserves explicit nil over generator" do
125+
result = FixtureBot.define(schema) do
126+
user.email { "#{name}@blog.test" }
127+
128+
user :admin do
129+
name "Brad"
130+
email nil
131+
end
132+
end
133+
134+
expect(result.tables[:users][:admin][:email]).to be_nil
135+
end
136+
124137
it "uses record_name as default name" do
125138
result = FixtureBot.define(schema) do
126139
user.email { "#{name}@blog.test" }

0 commit comments

Comments
 (0)