Improve error message for resolving invalid traits

Fixes [#1259]
Fixes [#1267]

In [#1156] we added support for looking up local traits with either a
symbol or string. This matches the lookup for factories and for global
traits.

We were calling `to_sym` on the trait arguments passed in when
building an object, assuming that those arguments would always respond
to `to_sym`. This leads to a confusing error message when passing an
object that doesn't respond to that method.

This PR replaces the confusing "NoMethodError: undefined method `to_sym`
for ..." with a more helpful "KeyError: Trait not registered: ...". It
ensures that all trait resolution is done using strings instead of
symbols, all objects should have a `to_s` method.

Co-authored-by: Sean Doyle <sean.p.doyle24@gmail.com>

[#1259]: https://github.com/thoughtbot/factory_bot/issues/1259
[#1267]: https://github.com/thoughtbot/factory_bot/issues/1267
[#1156]: https://github.com/thoughtbot/factory_bot/pull/1156
This commit is contained in:
Daniel Colson 2019-02-22 15:53:39 -05:00
parent 2958bfb38e
commit 6078d8c486
5 changed files with 17 additions and 4 deletions

View File

@ -115,7 +115,7 @@ module FactoryBot
end
def trait_for(name)
defined_traits.detect { |trait| trait.name == name }
defined_traits.detect { |trait| trait.name == name.to_s }
end
def initialize_copy(source)

View File

@ -5,7 +5,7 @@ module FactoryBot
@strategy = strategy
@overrides = traits_and_overrides.extract_options!
@traits = traits_and_overrides.map(&:to_sym)
@traits = traits_and_overrides
end
def run(runner_strategy = @strategy, &block)

View File

@ -4,7 +4,7 @@ module FactoryBot
attr_reader :name, :definition
def initialize(name, &block)
@name = name.to_sym
@name = name.to_s
@block = block
@definition = Definition.new(@name)

View File

@ -232,6 +232,19 @@ describe "trait indifferent access" do
end
end
describe "looking up traits that don't exist" do
it "raises a KeyError" do
define_class("User")
FactoryBot.define do
factory :user
end
expect { FactoryBot.build(:user, double("not a trait")) }.
to raise_error(KeyError)
end
end
describe "traits with callbacks" do
before do
define_model("User", name: :string)

View File

@ -1,7 +1,7 @@
RSpec::Matchers.define :have_trait do |trait_name|
match do |instance|
instance.defined_traits.any? do |trait|
trait.name == trait_name && trait.send(:block) == @block
trait.name == trait_name.to_s && trait.send(:block) == @block
end
end