Login integration test with rspec/devise

2020-08-05 18:25发布

问题:

I'm having troubles making an integration test, for the user login in my rails application, pass.

I'm using Rspec and capybara, as well as devise for user authentication

Here is my code :

requests/authentications_spec.rb

describe 'log in' do
  before { visit root_path }
  subject { page }

  describe 'should be able to log in' do
    before do
      user = FactoryGirl.create(:user)
      fill_in :user_email, with: user.email
      fill_in :user_password, with: user.password
      click_on 'Log in'
    end
    it { should have_link 'Log out' }
  end
end

factories/user_factory.rb

FactoryGirl.define do
  factory :user do
    sequence( :first_name )  { |n| "FirstName#{n}" }
    sequence( :last_name )  { |n| "LastName#{n}" }
    sequence( :email ) { |n| "foo#{n}@example.com" }
    password              'foobar'
    password_confirmation 'foobar'
    created_at            Time.now
    updated_at            Time.now
  end
end

_login_form.html.erb, This form is rendered in the application layout header.

<%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { id: 'login-mini-form' }) do |f| %>
  <%= f.email_field :email,       placeholder: 'Your email' %>
  <%= f.password_field :password, placeholder: '******' %>
  <%= f.submit "Log in", id: 'login-button' %>

  <%- if devise_mapping.rememberable? -%>
    <%= f.check_box :remember_me %> <%= f.label :remember_me %>
  <%- end -%>

<% end %>

In the layout I have something like that :

if user_signed_in?
  render 'devise/menu/logout_button'
else
  render 'devise/menu/login_form'
end

The test is giving me

1) User should be able to log in with valid credentials 
     Failure/Error: it { should have_link 'Log out' }
       expected link "Log out" to return something
     # ./spec/requests/authentications_spec.rb:117:in `block (6 levels) in <top (required)>'

Finished in 0.71406 seconds
8 examples, 2 failures, 2 pending

I don't get why my test is not passing. Any ideas ?

Thanks a lot !

Edit : I get the same behavior testing the registration with : expect { click_button register_button }.to change(User, :count).by 1, the test returns :

Failure/Error: expect { click_button register_button }.to change(User, :count).by 1
       count should have been changed by 1, but was changed by 0

回答1:

So, I have found what was not working :

describe 'log in' do
  before { visit root_path }
  subject { page }

  describe 'should be able to log in' do
    before do
      user = FactoryGirl.create(:user)
      fill_in :user_email, with: user.email
      fill_in :user_password, with: user.password
      click_on 'Log in'
    end
    it { should have_link 'Log out' }
  end

The correct code is in fact :

describe 'log in' do
  before { visit root_path }
    subject { page }

    describe 'should be able to log in' do
      before do
        user = FactoryGirl.create(:user)
        fill_in 'user_email', with: user.email
        fill_in 'user_password', with: user.password
        click_on 'Log in'
      end
      it { should have_link 'Log out' }
    end
  end
end

It seems Capybara fill_in method doesn't take a symbol as an argument for ids but only strings. Silly me.



回答2:

You didn't provide a subject for your expectation, so it looks like RSpec is using the result of the last expression. That last expression is your click_button, which doesn't return anything. You can't call should on nothing.

To fix this, you just need to specify that the page should have said link. I use Capybara and Selenium-Webdriver, so for me it'd look like page.should have_link.... My RSpec-fu is not strong enough to know if you should use page too, or substitute response, session, or something else.