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.