mirror of
https://github.com/thoughtbot/factory_bot.git
synced 2022-11-09 11:43:51 -05:00
975fc4ff29
## Enum traits
Given a Rails model with an enum attribute:
```rb
class Task < ActiveRecord::Base
enum status: {queued: 0, started: 1, finished: 2}
end
```
It is common for people to define traits for each possible value of the enum:
```rb
FactoryBot.define do
factory :task do
trait :queued do
status { :queued }
end
trait :started do
status { :started }
end
trait :finished do
status { :finished }
end
end
end
```
With this commit, those trait definitions are no longer necessary—they are defined automatically by factory_bot.
If automatically defining traits for enum attributes on every factory is not desired, it is possible to disable the feature by setting `FactoryBot.automatically_define_enum_traits = false` (see commit: [Allow opting out of automatically defining traits](5a20017351
)).
In that case, it is still possible to explicitly define traits for an enum attribute in a particular factory:
```rb
FactoryBot.automatically_define_enum_traits = false
FactoryBot.define do
factory :task do
traits_for_enum(:status)
end
end
```
It is also possible to use this feature for other enumerable values, not specifically tied to ActiveRecord enum attributes:
```rb
class Task
attr_accessor :status
end
FactoryBot.define do
factory :task do
traits_for_enum(:status, ["queued", "started", "finished"])
end
end
```
The second argument here can be an enumerable object, including a Hash or Array.
Closes #1049
Co-authored-by: Lance Johnson <lancejjohnson@gmail.com>
Co-authored-by: PoTa <pota@mosfet.hu>
Co-authored-by: Frida Casas <fridacasas.fc@gmail.com>
Co-authored-by: Daniel Colson <danieljamescolson@gmail.com>
161 lines
4 KiB
Ruby
161 lines
4 KiB
Ruby
describe "enum traits" do
|
|
context "when automatically_define_enum_traits is true" do
|
|
it "builds traits automatically for model enum field" do
|
|
define_model("Task", status: :integer) do
|
|
enum status: { queued: 0, started: 1, finished: 2 }
|
|
end
|
|
|
|
FactoryBot.define do
|
|
factory :task
|
|
end
|
|
|
|
Task.statuses.each_key do |trait_name|
|
|
task = FactoryBot.build(:task, trait_name)
|
|
|
|
expect(task.status).to eq(trait_name)
|
|
end
|
|
|
|
Task.reset_column_information
|
|
end
|
|
|
|
it "prefers user defined traits over automatically built traits" do
|
|
define_model("Task", status: :integer) do
|
|
enum status: { queued: 0, started: 1, finished: 2 }
|
|
end
|
|
|
|
FactoryBot.define do
|
|
factory :task do
|
|
trait :queued do
|
|
status { :finished }
|
|
end
|
|
|
|
trait :started do
|
|
status { :finished }
|
|
end
|
|
|
|
trait :finished do
|
|
status { :finished }
|
|
end
|
|
end
|
|
end
|
|
|
|
Task.statuses.each_key do |trait_name|
|
|
task = FactoryBot.build(:task, trait_name)
|
|
|
|
expect(task.status).to eq("finished")
|
|
end
|
|
|
|
Task.reset_column_information
|
|
end
|
|
|
|
it "builds traits for each enumerated value using a provided list of values as a Hash" do
|
|
statuses = { queued: 0, started: 1, finished: 2 }
|
|
|
|
define_class "Task" do
|
|
attr_accessor :status
|
|
end
|
|
|
|
FactoryBot.define do
|
|
factory :task do
|
|
traits_for_enum :status, statuses
|
|
end
|
|
end
|
|
|
|
statuses.each do |trait_name, trait_value|
|
|
task = FactoryBot.build(:task, trait_name)
|
|
|
|
expect(task.status).to eq(trait_value)
|
|
end
|
|
end
|
|
|
|
it "builds traits for each enumerated value using a provided list of values as an Array" do
|
|
statuses = %w[queued started finished]
|
|
|
|
define_class "Task" do
|
|
attr_accessor :status
|
|
end
|
|
|
|
FactoryBot.define do
|
|
factory :task do
|
|
traits_for_enum :status, statuses
|
|
end
|
|
end
|
|
|
|
statuses.each do |trait_name|
|
|
task = FactoryBot.build(:task, trait_name)
|
|
|
|
expect(task.status).to eq(trait_name)
|
|
end
|
|
end
|
|
|
|
it "builds traits for each enumerated value using a custom enumerable" do
|
|
statuses = define_class("Statuses") do
|
|
include Enumerable
|
|
|
|
def each(&block)
|
|
["queued", "started", "finished"].each(&block)
|
|
end
|
|
end.new
|
|
|
|
define_class "Task" do
|
|
attr_accessor :status
|
|
end
|
|
|
|
FactoryBot.define do
|
|
factory :task do
|
|
traits_for_enum :status, statuses
|
|
end
|
|
end
|
|
|
|
statuses.each do |trait_name|
|
|
task = FactoryBot.build(:task, trait_name)
|
|
|
|
expect(task.status).to eq(trait_name)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when automatically_define_enum_traits is false" do
|
|
it "raises an error for undefined traits" do
|
|
with_temporary_assignment(FactoryBot, :automatically_define_enum_traits, false) do
|
|
define_model("Task", status: :integer) do
|
|
enum status: { queued: 0, started: 1, finished: 2 }
|
|
end
|
|
|
|
FactoryBot.define do
|
|
factory :task
|
|
end
|
|
|
|
Task.statuses.each_key do |trait_name|
|
|
expect { FactoryBot.build(:task, trait_name) }.to raise_error(
|
|
KeyError, "Trait not registered: \"#{trait_name}\""
|
|
)
|
|
end
|
|
|
|
Task.reset_column_information
|
|
end
|
|
end
|
|
|
|
it "builds traits for each enumerated value when traits_for_enum are specified" do
|
|
with_temporary_assignment(FactoryBot, :automatically_define_enum_traits, false) do
|
|
define_model("Task", status: :integer) do
|
|
enum status: { queued: 0, started: 1, finished: 2 }
|
|
end
|
|
|
|
FactoryBot.define do
|
|
factory :task do
|
|
traits_for_enum(:status)
|
|
end
|
|
end
|
|
|
|
Task.statuses.each_key do |trait_name|
|
|
task = FactoryBot.build(:task, trait_name)
|
|
|
|
expect(task.status).to eq(trait_name)
|
|
end
|
|
|
|
Task.reset_column_information
|
|
end
|
|
end
|
|
end
|
|
end
|