I have a conditional in my view based upon a helper method defined in my application controller, which I defined as a helper method.
<% if logged_in? %>
When my spec hits this, it says:
ActionView::Template::Error:
undefined method `logged_in?' for #<#<Class:0x007fdc06b71aa8>:0x007fdc0b9b0930>
When I use my browser, it works perfect. I tried stubbing it, but I get another error when I try to stub it on the view or controller. This is what my test looks like:
it "has a logout link" do
render
expect(rendered).to have_link "Logout"
end
Here's my gemfile:
ruby "2.4.1"
gem "bootsnap", ">= 1.1.0", require: false
gem "coffee-rails", "~> 4.2"
gem "jbuilder", "~> 2.5"
gem "pg"
gem "puma", "~> 3.11"
gem "rails", "~> 5.2.1"
gem "rails-controller-testing"
gem "sass-rails", "~> 5.0"
gem "turbolinks", "~> 5"
gem "uglifier", ">= 1.3.0"
group :development, :test do
gem "byebug", platforms: %i[mri mingw x64_mingw]
end
group :development do
gem "listen", ">= 3.0.5", "< 3.2"
gem "spring"
gem "spring-watcher-listen", "~> 2.0.0"
gem "web-console", ">= 3.3.0"
end
group :test do
gem "capybara", ">= 2.15"
gem "chromedriver-helper"
gem "factory_bot_rails"
gem "rspec-rails", "~> 3.7"
gem "selenium-webdriver"
gem "shoulda-matchers", "~> 3.1"
end
Update to the accepted answer, it now seems necessary to use without_partial_double_verification
to get around the ActionView::Base does not implement: field_name
error.
Example code:
let(:logged_in) { true }
before(:each) do
without_partial_double_verification do
allow(view).to receive(:logged_in?).and_return(logged_in)
end
render
end
it 'has a logout link' do
expect(rendered).to have_link 'Logout'
end
context 'with no logged user' do
let(:logged_in) { false }
it 'has a login link' do
expect(rendered).to have_link 'Login'
end
end
View specs usually does not need to call the real helper (if you wan't to test the helper then you can do a helper spec).
It's faster and easier to just stub the helper method to return the value you want for your given test:
context 'with a logged user' do
before(:each) do
allow(view).to receive(:logged_in?).and_return(true)
end
it 'has a logout link' do
render
expect(rendered).to have_link 'Logout'
end
end
context 'with no logged user' do
before(:each) do
allow(view).to receive(:logged_in?).and_return(false)
end
it 'has a login link' do
render
expect(rendered).to have_link 'Login'
end
end
When you do model, controller, views, helper or any other isolated test, it does not have access to all the app since it's designed to run fast. For example: controller tests does not render views by default, model specs only tests the model, view specs do not have a context of the request nor session, etc.
You can have full real user tests using integration (feature) specs which runs the whole user interaction from beginning to end with access to everything, even controlling what the user clicks.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With