20

Testing a rails application which has before_filter :authenticate_user! for most controllers, I cannot get Capybara to preserve a session.

I have Capybara configured using PhantomJS with poltergeist.

I use the following helper:

require 'spec_helper'
include Warden::Test::Helpers

module FeatureHelpers
  def login(user = FactoryGirl.create(:default_user))
    login_as user, scope: :user
    user
  end
end

I have the following spec file:

require 'spec_helper'
include Warden::Test::Helpers

feature 'Leads Data Tasks View' do
  before(:each) do
    @user = login
  end

  after{ Warden.test_reset! }

  context "clicking a task button" do
    scenario "login persists across multuple actions", js: true do
      visit '/tasks'

      page.should have_selector('#parse', count: 1)
    end
  end
end

When I run the test as it's shown here, it will pass. However, if I invoke a click_link on something that performs AJAX actions, or if I simply try to do visit '/tasks' twice, the should assertion will fail because I'll get redirected to the login page of the app.

I've tried a few different approaches, including setting up a Capybara::Session, but I still get 401 codes on AJAX requests and I can only successfully visit once per spec.

What am I doing wrong?

asfallows
  • 5,998
  • 6
  • 29
  • 48
  • Based on the syntax your using, im guessing this is devise. Are you firing many ajax calls? Devise has some odd behaviour when dealing with ajax calls. See http://stackoverflow.com/questions/11845500/rails-devise-authentication-csrf-issue for more info – DickieBoy Sep 12 '13 at 11:30
  • Thank you for pointing me to that question. To answer your question, I am often firing many AJAX calls, however this issue appears to be happening even if I don't fire any. If I duplicate the `visit` call so that it simply loads the page twice, no AJAX happens in between. – asfallows Sep 12 '13 at 19:59
  • Additionally, for the sake of testing I decided to try both option 2 from the accepted answer in your linked question, as well as temporarily commenting out `protect_from_forgery` in my application controller. Neither of these changed the outcome; I still get 401 on all but the first request. – asfallows Sep 12 '13 at 20:05
  • Does this work if it was ran normally. i.e. A user using it? – DickieBoy Sep 13 '13 at 12:57
  • Yes, it works in all environments except automated tests (PhantomJS is headless, so it isn't launching Chrome/Firefox instances) – asfallows Sep 13 '13 at 13:19
  • Not sure if this will make a difference, but i use `Devise::Test::Helpers` instead of `Warden::Test::Helpers` – DickieBoy Sep 13 '13 at 13:40
  • According to https://github.com/plataformatec/devise/issues/1114, it's not recommended to use Devise::TestHelpers outside of controller specs. I tried swapping one out for the other and I got a pile of errors on my controller specs. – asfallows Sep 13 '13 at 15:24
  • 1
    Not sure if this will help but try forcing phantom js to use the same db connection. Have a look at this railscasts: http://railscasts.com/episodes/391-testing-javascript-with-phantomjs and try the code in `spec/support/shared_db_connection.rb` – j03w Sep 13 '13 at 22:31
  • This suggestion solved the problem! Would you mind writing up an answer that summarizes the solution so that I can accept it and give you the bounty? – asfallows Sep 16 '13 at 12:58

1 Answers1

25

So the problem was that phantomjs driver (poltergeist) was using a separated database connection. I had the exact same issue before and I got a solution from railscast episode 391 with the code in spec/support/shared_db_connection.rb

Since I can't find license for his code so I will just link to the code here

j03w
  • 3,679
  • 1
  • 21
  • 15
  • 5
    I suspect you use DatabaseCleaner gem, and you should tell it to use :truncation strategy explicitly for capybara tests. Also `self.use_transactional_fixtures = false`. This way you dont need to share connection. – Fedcomp Dec 15 '15 at 12:41
  • @Fedcomp Please remember that :truncation will most likely be very slow as actual DB writes and subsequent deletion will occur. Shared connection allows running specs in transactions, which is much faster. Try to make shared connection work, it's absolutely worth it. See also EvilMartian's TestProf gem, which provides the shared connection backport. – Epigene May 23 '19 at 06:32
  • That was not random answer but my experience. Capybara runs additional thread, that's why you can't just make it shared connection, and that's why you use truncation which is shared for everything unlike transaction. If you know how to defeat capybara with spinning up another thread and share the connection - let me know. Untill then that's probably the only solution. – Fedcomp May 23 '19 at 14:08