Why are helper methods not working in view specs?

Solution 1:

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.

Solution 2:

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