I've been stuck on trying to write a system test for a form that manually works in the browser.
I have a Speaker
model that has_one :individual
. The form field looks like this:
<fieldset>
<%= form.label :speaker, "Who said it?" %>
<%= form.collection_select :speaker_id, Speaker.all.sort_by(&:full_name), :id, :full_name %>
</fieldset>
The custom full_name
method in the Speaker
model looks like this:
def full_name
if individual
"#{individual.first_name} #{individual.last_name}"
end
end
The if individual
conditional is a smell, but without it, I get this error:
Minitest::UnexpectedError: ActionView::Template::Error: undefined method `first_name' for nil:NilClass
If I add the if individual
conditional then the error looks like this:
Minitest::UnexpectedError: ActionView::Template::Error: comparison of String with nil failed
I'm confused because I'm using a similar pattern to sort collection selects by a full_name
in other models, but this is the only one that raises an error in the system test. Also everything works as expected when I manually test in the browser.
I can also access the the first_name
last_name
and full_name
methods in the Individual
model in the console, no problem.
This also doesn't cause an error (and I can use :full_name
to display the name in the browser, but it's just not alphabetical:
<%= form.collection_select :speaker_id, Speaker.all, :id, :full_name %>
How can I fix this error in Capybara? Or is there a better way to return Speaker.all
in the collection_select sorted alphabetically?
Update:
I simplified this by not passing the Quote / Individual relationship through a Speaker model. Now, my Quote
model belongs_to :individual
and Individual
has_many :quotes
. This is also working in the browser, but I'm getting the same error with my system test:
<ActionView::Template::Error: undefined method `full_name' for nil:NilClass>
Here's one of the tests that is failing with this error...
require "application_system_test_case"
class QuotesTest < ApplicationSystemTestCase
setup do
@contributor = users(:contributor)
@contributor_quote = quotes(:contributor_quote)
@category = categories(:rock_and_roll)
@field = fields(:music)
@topic_one = topics(:recording)
@topic_two = topics(:songwriting)
@individual = individuals(:john_lennon)
@group = groups(:the_beatles)
end
test "visiting the index should be accessible to all" do
visit quotes_path
assert_text @contributor_quote.body
click_on @contributor_quote.body
assert_current_path quote_path(@contributor_quote)
end
end
My Individual
model has this method in it:
def full_name
"#{first_name} #{last_name}"
end
And this is the part of the view that is causing the failure:
Speaker: <%= @quote.individual.full_name %>
If I include save_and_open_page
the error looks like this...
I tried adding .strip
as Thomas' answer suggested, but that's not helping.
Again, the only problem is this system test. It works fine in the browser.
Without actually seeing any of the test code the error is coming from it's impossible to know for sure, and I have no idea where Capybara is fitting into this. I'm guessing that what you have is a Speaker model that seems to depend on there being an individual
associated with it, but that's not actually enforced anywhere so when you create the speaker instance in your test without an associated individual it's not being flagged as invalid. If Speaker is supposed to support there not being an associated individual
then your issue is that your full_name
method is returning nil when a string is required. To fix that you could do
def full_name
"#{individual&.first_name} #{individual&.last_name}".strip
end
to give you the full name when individual
does exist, and an empty string when it doesn't