mirror of
https://github.com/thoughtbot/factory_bot.git
synced 2022-11-09 11:43:51 -05:00
Fix self referencing trait error (#1294)
If a new trait is defined with attributes, check if attributes matches the name of the trait. Raise an error if so, to avoid a recursive call to the trait. Co-authored-by: Daniel Colsen <daniel.j.colson@thoughtbot.com> Co-authored-by: Paras Sanghavi <sanghaviparas@gmail.com>
This commit is contained in:
parent
831dcef717
commit
5ccc564923
4 changed files with 45 additions and 2 deletions
|
@ -25,6 +25,9 @@ module FactoryBot
|
||||||
[Attribute::Association.new(name, name, {})]
|
[Attribute::Association.new(name, name, {})]
|
||||||
elsif FactoryBot::Internal.sequences.registered?(name)
|
elsif FactoryBot::Internal.sequences.registered?(name)
|
||||||
[Attribute::Sequence.new(name, name, @ignored)]
|
[Attribute::Sequence.new(name, name, @ignored)]
|
||||||
|
elsif @factory.name.to_s == name.to_s
|
||||||
|
message = "Self-referencing trait '#{@name}'"
|
||||||
|
raise TraitDefinitionError, message
|
||||||
else
|
else
|
||||||
@factory.inherit_traits([name])
|
@factory.inherit_traits([name])
|
||||||
[]
|
[]
|
||||||
|
|
|
@ -2,6 +2,9 @@ module FactoryBot
|
||||||
# Raised when a factory is defined that attempts to instantiate itself.
|
# Raised when a factory is defined that attempts to instantiate itself.
|
||||||
class AssociationDefinitionError < RuntimeError; end
|
class AssociationDefinitionError < RuntimeError; end
|
||||||
|
|
||||||
|
# Raised when a trait is defined that references itself.
|
||||||
|
class TraitDefinitionError < RuntimeError; end
|
||||||
|
|
||||||
# Raised when a callback is defined that has an invalid name
|
# Raised when a callback is defined that has an invalid name
|
||||||
class InvalidCallbackNameError < RuntimeError; end
|
class InvalidCallbackNameError < RuntimeError; end
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,11 @@ module FactoryBot
|
||||||
@name = name.to_s
|
@name = name.to_s
|
||||||
@block = block
|
@block = block
|
||||||
@definition = Definition.new(@name)
|
@definition = Definition.new(@name)
|
||||||
|
|
||||||
proxy = FactoryBot::DefinitionProxy.new(@definition)
|
proxy = FactoryBot::DefinitionProxy.new(@definition)
|
||||||
proxy.instance_eval(&@block) if block_given?
|
|
||||||
|
if block_given?
|
||||||
|
proxy.instance_eval(&@block)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor,
|
delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor,
|
||||||
|
|
|
@ -798,3 +798,38 @@ describe "traits used in associations" do
|
||||||
expect(creator.name).to eq "Joe Creator"
|
expect(creator.name).to eq "Joe Creator"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "when a self-referential trait is defined" do
|
||||||
|
it "raises a TraitDefinitionError" do
|
||||||
|
define_model("User", name: :string)
|
||||||
|
FactoryBot.define do
|
||||||
|
factory :user do
|
||||||
|
trait :admin do
|
||||||
|
admin
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
expect { FactoryBot.build(:user, :admin) }.to raise_error(
|
||||||
|
FactoryBot::TraitDefinitionError,
|
||||||
|
"Self-referencing trait 'admin'",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises a TraitDefinitionError" do
|
||||||
|
define_model("User", name: :string)
|
||||||
|
FactoryBot.define do
|
||||||
|
factory :user do
|
||||||
|
trait :admin do
|
||||||
|
admin
|
||||||
|
name { "name" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
expect { FactoryBot.build(:user, :admin) }.to raise_error(
|
||||||
|
FactoryBot::TraitDefinitionError,
|
||||||
|
"Self-referencing trait 'admin'",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in a new issue