2
votes

I'm stuck trying to create integration tests using Capybara and MiniTest::Spec. I'm not using any 3rd party plugin for authentication. I'm using basic Authentication using has_secure_password built into rails 4.1

I have a helper that is looking for current_user which is created after authentication (pretty standard).

I've tried authenticating with Capybara then testing with visit:

test.rb

require 'test_helper'

describe "Admin area integration" do

setup do
  def current_user
    create(:admin_user, password: "test", password_confirmation: "test")
  end
end

teardown do
  current_user.destroy!
end

# results in error below
it "visits admin area path" do
  visit admin_area_path
  page.text.must_include('Dashboard')
end

# test passes
it "test user login" do
  visit "/login"
  within("#login_form") do
    fill_in('email', with: current_user.email)
    fill_in('password', with: "test")
  end
  click_button('login')
  has_content?('Welcome')
end

end

Error

undefined method `email' for nil:NilClass app/helpers/application_helper.rb

Is there a way to pass the current_user object using capybara visit or am I missing something simple so the helper will not throw an error?

1

1 Answers

3
votes

You are not supposed to modify internals of your Rails app, when doing integration tests. These tests should simulate the real world behaviour - a user visiting your site with a browser. So there is no way to pass the current_user object to capybara, like there is no way to modify the user session for your user from outside the app.

The straightforward way would be extracting the login steps(filling out the form) into separate function within some other test file( we usually have them all in test/support/** and just require all supporting functions in spec_helper). Then you repeat the login steps before any other test, which requires the user to be logged in.

However once we have tested the login, we can rely on it and the repetitive task of login the user each time can become quite annoying. It wouldn't be Ruby otherwise, when there wasn't a way to patch your app behaviour, while in test mode.

You can try using some mocking/stubbing lib and just stub the current_user method on any instance of the class which is holding it. Mocha example:

require 'mocha'    
ApplicationController.any_instance.stubs(:current_user).returns(User.new {...})   

The other option would be to modify the rack session directly. I expect your are storing the user_id in the session, and your current_user method just loads the user with that id. So you can just require the rack_session_accessgem within your testsuite and set the user_id of your test user.

Remember also to disable transactional fixtures at least for the integration tests and use database_cleaner instead. Otherwise capybara will not be able to see any of your test data created, because it will be in an uncommitted transaction which is only accessible for the initiating thread.

See Configuring database_cleaner with Rails, RSpec, Capybara, and Selenium