Skip to content

Commit

Permalink
Support file_fixture in Factory definitions
Browse files Browse the repository at this point in the history
Related to [factory_bot#1282][]

[rails/rails#45606][] has been merged and is likely to be released as
part of Rails 7.1.

With that addition, the path toward resolving [factory_bot#1282][]
becomes more clear. If factories can pass along [Pathname][] instances
to attachment attributes, Active Support will handle the rest.

Instances of `ActiveSupport::TestCase` provide a [file_fixture][] helper
to construct a `Pathname` instance based on the path defined by
`ActiveSupport::TestCase.file_fixture_path` (relative to the Rails root
directory).

[factory_bot#1282]: thoughtbot/factory_bot#1282 (comment)
[rails/rails#45606]: rails/rails#45606
[Pathname]: https://docs.ruby-lang.org/en/master/Pathname.html
[file_fixture]: https://api.rubyonrails.org/classes/ActiveSupport/Testing/FileFixtures.html#method-i-file_fixture
  • Loading branch information
seanpdoyle committed Jan 10, 2025
1 parent 346e3c7 commit 43e18b9
Show file tree
Hide file tree
Showing 16 changed files with 193 additions and 69 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ jobs:
ruby-version: ${{ matrix.ruby }}
- name: Setup project
run: bundle install
- name: Run test
run: bundle exec rake
- name: RSpec specs
run: bundle exec rake spec
- name: Minitest tests
run: bundle exec rake test

standard:
name: Run standard
Expand Down
13 changes: 13 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,21 @@ GEM
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
activejob (7.1.2)
activesupport (= 7.1.2)
globalid (>= 0.3.6)
activemodel (7.1.2)
activesupport (= 7.1.2)
activerecord (7.1.2)
activemodel (= 7.1.2)
activesupport (= 7.1.2)
timeout (>= 0.4.0)
activestorage (7.1.2)
actionpack (= 7.1.2)
activejob (= 7.1.2)
activerecord (= 7.1.2)
activesupport (= 7.1.2)
marcel (~> 1.0)
activesupport (7.1.2)
base64
bigdecimal
Expand Down Expand Up @@ -92,6 +101,8 @@ GEM
activesupport (>= 5.0.0)
ffi (1.15.5)
ffi (1.15.5-java)
globalid (1.2.1)
activesupport (>= 6.1)
i18n (1.14.5)
concurrent-ruby (~> 1.0)
io-console (0.7.2)
Expand All @@ -107,6 +118,7 @@ GEM
loofah (2.22.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
marcel (1.0.4)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2023.0218.1)
Expand Down Expand Up @@ -228,6 +240,7 @@ PLATFORMS

DEPENDENCIES
activerecord (>= 5.0.0)
activestorage (>= 5.0.0)
appraisal
aruba
cucumber
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,19 @@ using an empty array:
config.factory_bot.definition_file_paths = []
```

### File Fixture Support

Factories have access to [ActiveSupport::Testing::FileFixtures#file_fixture][]
helper to read files from tests.

To disable file fixture support, set `file_fixture_support = false`:

```rb
config.factory_bot.file_fixture_support = false
```

[ActiveSupport::Testing::FileFixtures#file_fixture]: https://api.rubyonrails.org/classes/ActiveSupport/Testing/FileFixtures.html#method-i-file_fixture

### Generators

Including factory\_bot\_rails in the development group of your Gemfile
Expand Down
3 changes: 3 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require "bundler/setup"
require "cucumber/rake/task"
require "rspec/core/rake_task"
require "minitest/test_task"
require "standard/rake"

Bundler::GemHelper.install_tasks name: "factory_bot_rails"
Expand All @@ -12,5 +13,7 @@ end

RSpec::Core::RakeTask.new(:spec)

Minitest::TestTask.create

desc "Run the test suite and standard"
task default: %w[spec cucumber standard]
1 change: 1 addition & 0 deletions factory_bot_rails.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ Gem::Specification.new do |s|

s.add_development_dependency("sqlite3")
s.add_development_dependency("activerecord", ">= 5.0.0")
s.add_development_dependency("activestorage", ">= 5.0.0")
end
9 changes: 9 additions & 0 deletions lib/factory_bot_rails/file_fixture_support.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module FactoryBotRails
module FileFixtureSupport
def self.included(klass)
klass.cattr_accessor :file_fixture_support

klass.delegate :file_fixture, to: "self.class.file_fixture_support"
end
end
end
18 changes: 18 additions & 0 deletions lib/factory_bot_rails/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
require "factory_bot_rails/generator"
require "factory_bot_rails/reloader"
require "factory_bot_rails/factory_validator"
require "factory_bot_rails/file_fixture_support"
require "rails"

module FactoryBotRails
class Railtie < Rails::Railtie
config.factory_bot = ActiveSupport::OrderedOptions.new
config.factory_bot.definition_file_paths = FactoryBot.definition_file_paths
config.factory_bot.validator = FactoryBotRails::FactoryValidator.new
config.factory_bot.file_fixture_support = true

initializer "factory_bot.set_fixture_replacement" do
Generator.new(config).run
Expand All @@ -20,6 +22,22 @@ class Railtie < Rails::Railtie
FactoryBot.definition_file_paths = definition_file_paths
end

config.after_initialize do
if config.factory_bot.file_fixture_support
FactoryBot::SyntaxRunner.include FactoryBotRails::FileFixtureSupport

ActiveSupport.on_load :active_support_test_case do
setup { FactoryBot::SyntaxRunner.file_fixture_support = self }
end

if defined?(RSpec) && RSpec.respond_to?(:configure)
RSpec.configure do |config|
config.before { FactoryBot::SyntaxRunner.file_fixture_support = self }
end
end
end
end

config.after_initialize do |app|
FactoryBot.find_definitions
Reloader.new(app).run
Expand Down
40 changes: 40 additions & 0 deletions spec/factory_bot_rails/factory_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# frozen_string_literal: true

require "spec_helper"

describe "factory extensions" do
describe "#file_fixture" do
it "delegates to the test harness" do
FactoryBot.define do
factory :upload, class: Struct.new(:filename) do
filename { file_fixture("file.txt") }
end
end

upload = FactoryBot.build(:upload)

expect(Pathname(upload.filename)).to eq(file_fixture("file.txt"))
end

it "uploads an ActiveStorage::Blob" do
FactoryBot.define do
factory :active_storage_blob, class: ActiveStorage::Blob do
filename { pathname.basename }

transient do
pathname { file_fixture("file.txt") }
end

after :build do |model, factory|
model.upload factory.pathname.open
end
end
end

blob = FactoryBot.create(:active_storage_blob)

expect(blob.filename.to_s).to eq("file.txt")
expect(blob.download).to eq(file_fixture("file.txt").read)
end
end
end
13 changes: 13 additions & 0 deletions spec/fake_app.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# frozen_string_literal: true

ENV["DATABASE_URL"] = "sqlite3::memory:"

require "active_record/railtie"
require "active_storage/engine"

module Dummy
class Application < Rails::Application
config.eager_load = false
Expand All @@ -8,6 +13,14 @@ class Application < Rails::Application
if Rails.gem_version >= Gem::Version.new("7.1")
config.active_support.cache_format_version = 7
end

config.active_storage.service = :local
config.active_storage.service_configurations = {
local: {
root: root.join("tmp/storage"),
service: "Disk"
}
}
end
end

Expand Down
Empty file added spec/fixtures/files/file.txt
Empty file.
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

require "factory_bot_rails"
require "fake_app"
require "rspec/rails"

Dir["spec/support/**/*.rb"].each { |f| require File.expand_path(f) }

Expand Down
27 changes: 27 additions & 0 deletions spec/support/active_record/migrations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

ActiveStorage::Engine.root.glob("db/migrate/*.rb").each { |file| require file }

ActiveSupport.on_load :active_support_test_case do
setup do
CreateActiveStorageTables.migrate :up
end

teardown do
CreateActiveStorageTables.migrate :down
rescue ActiveRecord::StatementInvalid
# no-op
end
end

defined?(RSpec) && RSpec.configure do |config|
config.before do
CreateActiveStorageTables.migrate :up
end

config.after do
CreateActiveStorageTables.migrate :down
rescue ActiveRecord::StatementInvalid
# no-op
end
end
67 changes: 0 additions & 67 deletions spec/support/macros/define_constant.rb

This file was deleted.

40 changes: 40 additions & 0 deletions test/factory_bot_rails/factory_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# frozen_string_literal: true

require "test_helper"

class FactoryBotRails::FactoryTest < ActiveSupport::TestCase
self.file_fixture_path = "test/fixtures/files"

test "delegates #file_fixture to the test harness" do
FactoryBot.define do
factory :upload, class: Struct.new(:filename) do
filename { file_fixture("file.txt") }
end
end

upload = FactoryBot.build(:upload)

assert_equal file_fixture("file.txt"), upload.filename
end

test "uploads an ActiveStorage::Blob" do
FactoryBot.define do
factory :active_storage_blob, class: ActiveStorage::Blob do
filename { pathname.basename }

transient do
pathname { file_fixture("file.txt") }
end

after :build do |model, factory|
model.upload factory.pathname.open
end
end
end

blob = FactoryBot.create(:active_storage_blob)

assert_equal "file.txt", blob.filename.to_s
assert_equal file_fixture("file.txt").read, blob.download
end
end
Empty file added test/fixtures/files/file.txt
Empty file.
11 changes: 11 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

# Configure Rails Environment
ENV["RAILS_ENV"] = "test"

require_relative "../spec/fake_app"

require "rails/test_help"
require "factory_bot_rails"

Dir["spec/support/**/*.rb"].each { |f| require File.expand_path(f) }

0 comments on commit 43e18b9

Please sign in to comment.