Search code examples
ruby-on-railsrspeccapybararspec-rails

RSpec tests pass in isolation, but fail when run together


In my code_controller_spec.rb my tests pass when I just run the tests in code_controller_spec.rb. However, when I run the suite, only the create, edit, and update tests fail within code_controller_spec.rb. I'm really not sure where to go from here and I really don't know why my tests fail when running together. I have config.use_transactional_fixtures = false and am using database_cleaner. My app works fine locally with the below actions and I don't receive any errors when creating or updating a post. Let me know if you need additional info.

When I run the suite, the failures I get are:

1) CodesController admin pages #create posts a new code post
     Failure/Error:
       post :create, params: {
         code: { 
           created_at: Date.today, 
           title: "Code things", 
           content: "The content of the code post",
           user_id: user.id
         }
       }

     ActionController::UrlGenerationError:
       No route matches {:action=>"create", :code=>{:created_at=>Fri, 20 Oct 2017, :title=>"Code things", :content=>"The content of the code post", :user_id=>1}, :controller=>"codes"}

2)  CodesController admin pages #edit edits a code post
     Failure/Error: get :edit, params: { id: code }

     ActionController::UrlGenerationError:
       No route matches {:action=>"edit", :controller=>"codes", :id=>#<Code id: 1, title: "Code post title", content: "Coding speak that not everyone can understand...", created_at: "2017-10-20 00:00:00", updated_at: "2017-10-21 06:05:27", user_id: 2>}

3) CodesController admin pages #update updates a code post
     Failure/Error: put :update, params: { id: code, code: code2 }

     ActionController::UrlGenerationError:
       No route matches {:action=>"update", :code=>{:title=>"Updated title", :content=>"Updated content"}, :controller=>"codes", :id=>#<Code id: 1, title: "Code post title", content: "Coding speak that not everyone can understand...", created_at: "2017-10-20 00:00:00", updated_at: "2017-10-21 06:05:27", user_id: 2>}

My spec/controllers/user/codes_controller_spec.rb

RSpec.describe User::CodesController, type: :controller do

  let!(:user) { User.create(email: "user@example.com", password: "password") }
  let!(:code) { FactoryGirl.create(:code) }

  before do
    sign_in_as user
    expect(response).to have_http_status(:success)
  end

  describe "admin pages" do
    render_views

    context "#create" do
      it "posts a new code post" do
        post :create, params: {
          code: { 
            created_at: Date.today, 
            title: "Code things", 
            content: "The content of the code post",
            user_id: user.id
          }
        }
        expect(response).to redirect_to user_codes_path
        expect(flash[:success]).to eq "Post created successfully."
      end
    end

    context "#edit" do
      it "edits a code post" do
        get :edit, params: { id: code }
        expect(response).to render_template :edit
      end
    end

    context "#update" do
      let(:code2) do 
        { title: "Updated title", content: "Updated content" }
      end
      it "updates a code post" do
        put :update, params: { id: code, code: code2 }
        code.reload
        expect(response).to redirect_to user_code_path(code)
        expect(code.title).to eq code2[:title]
        expect(code.content).to eq code2[:content]
        expect(flash[:success]).to eq "Post updated successfully."
      end
    end
  end
end

My spec/factories/post_factories.rb

FactoryGirl.define do
  factory :code do
    created_at Date.today
    title "Code post title"
    content "Coding speak that not everyone can understand..."

    association :user, factory: :user
  end

  factory :life do
    created_at Date.today
    title "Life post title"
    content "The world moves in mysterious ways; whether we want it to..."

    association :user, factory: :user
  end
end

I run rspec --seed 123 --bisect and then I run the output of that, but all my tests pass. I should mention I'm very new to --bisect.

This is the rspec --seed 123 --bisect output and when I run this all my tests pass.

rspec ./spec/controllers/user/codes_controller_spec.rb[1:1:1:1,1:1:2:1,1:1:3:1,1:1:4:1,1:1:5:1] ./spec/controllers/user/lives_controller_spec.rb[1:1:1,1:1:2] ./spec/features/admin_create_posts_spec.rb[1:1,1:2,1:3,1:4] ./spec/features/admin_edit_post_spec.rb[1:1,1:2,1:3] ./spec/features/clearance/user_signs_out_spec.rb[1:1] ./spec/features/clearance/visitor_resets_password_spec.rb[1:1,1:2,1:3,1:4,1:5,1:6] ./spec/features/clearance/visitor_signs_in_spec.rb[1:1,1:2,1:3,1:4,1:5,1:6,1:7,1:8] ./spec/features/clearance/visitor_signs_up_spec.rb[1:1,1:2,1:3,1:4,1:5,1:6,1:7,1:8] ./spec/features/clearance/visitor_updates_password_spec.rb[1:1,1:2,1:3] ./spec/features/homepage_spec.rb[1:1,1:2] ./spec/features/login_users_spec.rb[1:1,1:2] ./spec/features/logout_user_spec.rb[1:1] ./spec/features/showing_all_posts_spec.rb[1:1,1:2] ./spec/helpers/codes_helper_spec.rb[1:1] ./spec/helpers/lives_helper_spec.rb[1:1] ./spec/helpers/user/codes_helper_spec.rb[1:1] ./spec/helpers/user/lives_helper_spec.rb[1:1] ./spec/helpers/users_helper_spec.rb[1:1] ./spec/helpers/welcome_helper_spec.rb[1:1] ./spec/models/code_spec.rb[1:1] ./spec/models/life_spec.rb[1:1]

My database_cleaner config in rails_helper.rb

require database_cleaner

RSpec.configure do |config|
  config.use_transactional_fixtures = false

  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  # config.fixture_path = "#{::Rails.root}/spec/fixtures"

  config.before(:all) do
    FactoryGirl.reload
  end

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, remove the following line or assign false
  # instead of true.

  config.before(:suite) do
    if config.use_transactional_fixtures?
      raise(<<-MSG)
        Delete line `config.use_transactional_fixtures = true` from rails_helper.rb (or set it to false) to prevent uncommitted transactions being used in JavaScript-dependent specs.
                During testing, the app-under-test that the browser driver connects to uses a different database connection to the database connection used by the spec. The app's database connection would not be able to access uncommitted transaction data setup over the spec's database connection.
      MSG
    end
    DatabaseCleaner.clean_with(:truncation)
  end  

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, type: :feature) do
    # :rack_test driver's Rack app under test shares database connection
    # with the specs, so continue to use transaction strategy for speed.
    driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test

    if !driver_shares_db_connection_with_specs
      # Driver is probably for an external browser with an app under test that does *not*
      # share a database connection with the specs, so use truncation strategy.
      DatabaseCleaner.strategy = :truncation
    end
  end

  # adds this from
  # https://stackoverflow.com/questions/37753251/actionmailer-not-delivering-confirmation-emails-in-test-environment-rails-4
  config.before(:each, truncation: true) do 
    Database::Cleaner.strategy = :truncation 
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.append_after(:each) do
    DatabaseCleaner.clean
  end
end

UPDATED Output for rails routes

Prefix Verb   URI Pattern                             Controller#Action
              root GET    /                                       welcome#index
         passwords POST   /passwords(.:format)                    clearance/passwords#create
      new_password GET    /passwords/new(.:format)                clearance/passwords#new
           session POST   /session(.:format)                      clearance/sessions#create
edit_user_password GET    /users/:user_id/password/edit(.:format) clearance/passwords#edit
     user_password PATCH  /users/:user_id/password(.:format)      clearance/passwords#update
                   PUT    /users/:user_id/password(.:format)      clearance/passwords#update
                   POST   /users/:user_id/password(.:format)      clearance/passwords#create
             users POST   /users(.:format)                        clearance/users#create
           sign_in GET    /sign_in(.:format)                      clearance/sessions#new
          sign_out DELETE /sign_out(.:format)                     clearance/sessions#destroy
                   GET    /sign_out(.:format)                     clearance/sessions#destroy
           sign_up GET    /sign_up(.:format)                      clearance/users#new
        user_lives GET    /user/lives(.:format)                   user/lives#index
                   POST   /user/lives(.:format)                   user/lives#create
     new_user_life GET    /user/lives/new(.:format)               user/lives#new
    edit_user_life GET    /user/lives/:id/edit(.:format)          user/lives#edit
         user_life GET    /user/lives/:id(.:format)               user/lives#show
                   PATCH  /user/lives/:id(.:format)               user/lives#update
                   PUT    /user/lives/:id(.:format)               user/lives#update
                   DELETE /user/lives/:id(.:format)               user/lives#destroy
        user_codes GET    /user/codes(.:format)                   user/codes#index
                   POST   /user/codes(.:format)                   user/codes#create
     new_user_code GET    /user/codes/new(.:format)               user/codes#new
    edit_user_code GET    /user/codes/:id/edit(.:format)          user/codes#edit
         user_code GET    /user/codes/:id(.:format)               user/codes#show
                   PATCH  /user/codes/:id(.:format)               user/codes#update
                   PUT    /user/codes/:id(.:format)               user/codes#update
                   DELETE /user/codes/:id(.:format)               user/codes#destroy
             lives GET    /lives(.:format)                        lives#index
              life GET    /lives/:id(.:format)                    lives#show
             codes GET    /codes(.:format)                        codes#index
              code GET    /codes/:id(.:format)                    codes#show

Solution

  • I believe this is an autoload issue. If your ::CodesController gets loaded before the Users::CodesController then your spec for Users::CodesController is actually using ::CodesController and hence can't create the correct routes. When run singly the correct class is autoloaded and everything works correctly. To fix this require the correct class at the beginning of your spec.

    # spec/controllers/user/codes_controller_spec.rb
    
    require 'user/codes_controller'
    ...
    

    and

    # spec/controllers/codes_controller_spec.rb
    
    require 'codes_controller'
    ...