2

I'm using devise to handle the authentication process. I am now developing integration tests for my application, starting with the sign in process.

RSpec.describe 'sign in', type: :feature, js: true do
  let!(:user) { create(:user)}

  scenario 'sign in with correct credentials' do
    visit new_user_session_path
    fill_in 'Login', with: 'email@email.com'
    fill_in 'Password', with: 'password'
    click_on 'Sign in'
    expect(current_path).to eq(signed_in_path)
  end
end

After the test above clicks on the "Sign in" button, a session is created as intended and then the user is redirected to the signed_in_path. After this redirection, the controller for this path is called and it has a before_action :authenticate_user.

The problem is, after the redirect, this authenticate_user method doesn't recognize the current_user anymore which makes it redirect back to the sign in page and causes the test to fail.

What is causing this loss of session? How can I fix it?

PS: I've included config.include Devise::Test::IntegrationHelpers, type: :feature to my rails_helper.rb and the sign_in helper works great, but I shouldn't use this to test if the sign is page is working correctly.

mauriciomta
  • 47
  • 1
  • 5
  • 1
    You should at least change your spec to `fill_in 'Login', with: user.email` etc instead of hardcoding the values. – max Nov 25 '18 at 05:19

1 Answers1

1

A few potential issues here but the most likely is that click_on doesn't wait for any actions triggered by the click to occur (because it has no way of knowing what those actions will be). This is why most (if not all) of Capybaras finders/matchers/assertions/etc have waiting/retrying builtin, in order to give the site/app time for things to occur. The problem is you've not using the Capybara provided matcher, so your expectation just fails immediately, the tests ends, and the database connection is cleaned up (probably while the user is being redirected). To fix this you should always use the Capybara provided matchers when dealing with Capybara returned values/objects (ie never use eq with the current path)

expect(page).to have_current_path(signed_in_path)

A second potential (or could be both) is if the domain being redirected to is not he same as the domain login is occurring on. For instance if login is happening at http://127.0.0.1/... but redirection is going to http://localhost... then the session cookie will be set for the wrong domain and the user will no longer be logged in.

Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78
  • Thanks for the help but it still doesn't work. I made a little trick to make the test pass which was to remove the `before_action :authenticate_user` and hardcode the `current_user` with `current_user = User.last` `sign_in current_user` at the beginning of the action at the controller and it worked. Obviously I can't do that on the code but it shows that the problem is not timing but the fact that the `current_user` isn't being held after the redirect – mauriciomta Nov 25 '18 at 13:51
  • @mauriciomta Without knowing whether `current_user` is actually used on the `signed_in_path` I don't know that your "trick" actually proves anything, since `User.last` can return nil and IIRC calling `sign_in` with nil just ends up doing nothing. All it shows is that without the before_action it doesn't care if there's a valid user or not. What you need to check is that the email and password are correct for the user created, then check your test.log to see what requests are actually being made, and finally look at the page that the test does finally redirect to for any error messages. – Thomas Walpole Nov 25 '18 at 18:00
  • 1
    @mauriciomta The other thing to verify is that the domain name redirected to matches the domain name Capybara is going to -- ie if you're logging in to `127.0.0.1` but it's redirecting to `localhost` then the session cookie won't be for the correct domain and the user won't actually be logged in. – Thomas Walpole Nov 25 '18 at 18:06
  • Hey thanks, you are right on your last comment. I added `Capybara.server_host = 'localhost'` and it worked :) It would be cool to add it to the answer! – mauriciomta Nov 25 '18 at 21:23