Search code examples
ruby-on-railsruby-on-rails-4capybararspec-rails

Keeping user in the database between tests using Capybara?


My issue is that I have to create a new user and login for each individual capybara test.

An example is below:

require 'spec_helper'

describe "users" do
  describe "user registration" do
    it "should create a new user and log in" do
      # Register a new user to be used during the testing process
      visit signup_path
      fill_in 'Email', with: 'testuser'
      fill_in 'Password', with: 'testpass'
      fill_in 'Password confirmation', with: 'testpass'
      click_button 'Create User'
      current_path.should == root_path
      page.should have_content 'Thank you for signing up!'
    end
  end

  describe "user login" do
    it "should log in" do

      # log in
      visit login_path
      fill_in 'Email', with: 'testuser'
      fill_in 'Password', with: 'testpass'
      click_button 'Log In'
      current_path.should == root_path
      page.should have_content 'Logged in!'
    end
  end
end

The login test fails because the user no longer exists in the database for that test.

This could be fixed simply by putting both in one test, but I believe that is bad practice.

Also I have another file which currently is registering and logging in between each test using a before_do, which also seems to be quite bad... you can see that code here.

For the record this is my first rails app so perhaps I am trying to do this the wrong way. I would like to dry it up as much as possible..

Is capybara really this bad to use on pages that require user login?


Solution

  • I have done it this way.

    require "spec_helper"
    
      describe "Users" do
         subject { page }
         describe "User Registration" do
            before { visit signup_path }
    
            let(:submit) { "Sign up" }
    
            describe "with invalid information" do
               it "should not create a user" do
                 expect { click_button submit }.not_to change(User, :count)
               end
            end
    
            describe "with valid information" do
               before do
                 fill_in "Email",        with: "[email protected]"
                 fill_in "Password",     with: "foobar12"
                 fill_in "Password confirmation", with: "foobar12"
               end
    
               it "should create a user" do
                  expect { click_button submit }.to change(User, :count).by(1)
               end
    
               describe "after registration" do
                 before { click_button submit }
                 it { should have_content 'Thank you for signing up!' }
               end
    
               describe "after registration signout and login" do
                  let(:user) { User.find_by_email('[email protected]') }
                  before do
                    click_button submit 
                    visit signout_path
                    sign_in user     # sign_in is a method which u can define in your spec/support/utilities.rb . Define once and use at multiple places.
                  end
                  it { should have_content 'Logged In!' }
                  it { should have_link('Logout') }
               end
            end
         end    
       end
    

    # spec/support/utilities.rb

    def sign_in(user)
      visit sign_path
      fill_in "Email",    with: user.email
      fill_in "Password", with: user.password
      click_button "Log in" 
    end
    

    your every describe and it block will run after the before block in parent that's why we need to click_button in every block in above test cases.