0
votes

I'm trying to create a login action within a helper module that will create a new user and log me in as that user. Since I am using capybara with capybara-webkit driver, the post or submit methods are not available, so I can't simply post to the login path with the proper parameters. My current approach then is to actually visit the login path and fill out the login form with the newly created user's username and password. Here's the helper function I'm trying to create (in spec/support/session_macros.rb):

module SessionMacros
  def log_in
    user = User.create(first_name: 'Test',
               last_name: 'Test',
               email: '[email protected]',
               password: 'secret',
               password_confirmation: 'secret'
           )
    visit admin_login_path
    fill_in 'email', with: user.email
    fill_in 'password', with: 'secret'
    click_button 'Log in'
  end
end

In spec/spec_helper.rb:

config.include SessionMacros

In config/routes.rb:

  namespace :admin do
    resources :sessions
    get 'login', to: 'sessions#new', as: 'login'
    get 'logout', to: 'sessions#destroy', as: 'logout'
  end

In app/views/admin/sessions/new.html.haml

.login-form
  %h3 Sign in
  = form_tag admin_sessions_path do
    = content_tag :div, flash[:alert], class: 'alert' if flash[:alert]
    = text_field_tag :email, params[:email], placeholder: 'Email'
    = password_field_tag :password, params[:password], placeholder: 'Password'
    = submit_tag "Log in", class: 'button'

In app/controllers/admin/sessions_controller.rb

def create
  user = User.find_by_email(params[:email])
  if user && user.authenticate(params[:password])
    session[:user_id] = user.id
    redirect_to admin_root_url
  else
    flash[:alert] = 'Invalid email or password'
    redirect_to admin_login_path
  end
end

I'm using the helper in a feature spec (spec/features/admin/events_spec.rb):

before :each do
  log_in
  visit admin_events_path
end

The problem is that tests that I run with :js => true will result in the sessions_controller#create function not being able to see the user that was created at the beginning of the log_in method. Here's the result of some console testing that I did:

[5, 14] in /Users/Me/projects/cms/spec/support/session_macros.rb
   5                 email: '[email protected]',
   6                 password: 'secret',
   7                 password_confirmation: 'secret'
   8             )
   9      debugger
=> 10      visit admin_login_path
   11      fill_in 'email', with: user.email
   12      fill_in 'password', with: 'secret'
   13      click_button 'Log in'
   14    end
(rdb:1) User.all
[#<User id: 1, email: "[email protected]", password_digest: "$2a$10$Pxv3GlNnEPx0PnFOmP/MUeP0SMs4vD925vjhoaViKA8o...", created_at: "2013-12-29 20:34:47", updated_at: "2013-12-29 20:34:47", first_name: "Test", last_name: "Test">]
(rdb:1) continue
/Users/Me/projects/cms/app/controllers/admin/sessions_controller.rb:7
if user && user.authenticate(params[:password])

[2, 11] in /Users/Me/projects/cms/app/controllers/admin/sessions_controller.rb
   2    skip_before_filter :authorize, :authenticate
   3
   4    def create
   5      user = User.find_by_email(params[:email])
   6      debugger
=> 7      if user && user.authenticate(params[:password])
   8        session[:user_id] = user.id
   9        redirect_to admin_root_url
   10      else
   11        flash[:alert] = 'Invalid email or password'
(rdb:6) User.all
[]
(rdb:6)

Note that when I don't use :js => true it works fine:

[5, 14] in /Users/Me/projects/cms/spec/support/session_macros.rb
   5                 email: '[email protected]',
   6                 password: 'secret',
   7                 password_confirmation: 'secret'
   8             )
   9      debugger
=> 10      visit admin_login_path
   11      fill_in 'email', with: user.email
   12      fill_in 'password', with: 'secret'
   13      click_button 'Log in'
   14    end
(rdb:1) User.all
[#<User id: 1, email: "[email protected]", password_digest: "$2a$10$ryLIQcV7foWQdWLSObzUnuGsbAPzKvPVe2PRzGuTEGRM...", created_at: "2013-12-29 20:37:47", updated_at: "2013-12-29 20:37:47", first_name: "Test", last_name: "Test">]
(rdb:1) continue
/Users/Me/projects/cms/app/controllers/admin/sessions_controller.rb:7
if user && user.authenticate(params[:password])

[2, 11] in /Users/Me/projects/cms/app/controllers/admin/sessions_controller.rb
   2    skip_before_filter :authorize, :authenticate
   3
   4    def create
   5      user = User.find_by_email(params[:email])
   6      debugger
=> 7      if user && user.authenticate(params[:password])
   8        session[:user_id] = user.id
   9        redirect_to admin_root_url
   10      else
   11        flash[:alert] = 'Invalid email or password'
(rdb:1) User.all
[#<User id: 1, email: "[email protected]", password_digest: "$2a$10$ryLIQcV7foWQdWLSObzUnuGsbAPzKvPVe2PRzGuTEGRM...", created_at: "2013-12-29 20:37:47", updated_at: "2013-12-29 20:37:47", first_name: "Test", last_name: "Test">]

This happens both when I use Selenium and webkit drivers for javascript. What gives here? I am concerned that I may be fundamentally misunderstanding database interactions when doing JS integration testing with Capybara. I am also worried this might be an XY problem as I am not even sure about my log_in method approach. If someone could shed some light on either a better way to implement my log_in helper that can be compatible with Javascript, or why my database objects are nowhere to be found in my controllers in Javascript mode, I'd really appreciate it.

1

1 Answers

0
votes

It seems RSpec use database transactions for each test and any changing in this transaction is invisible for application code. Play around use_transactional_fixtures option (1) of Rspec, Capybara docs (2) and database_cleaner gem (3)