Search code examples
ruby-on-railsphantomjscapybaramechanizepoltergeist

What can cause Capybara::Poltergeist::TimeoutError: in group testing that doesn't individually?


A Rails app that uses remote testing to test a CakePHP app running on a Vagrant Ubuntu VM. My OS is macOS High Sierra.

'rspec/rails'
'capybara/rails'
'capybara/mechanize'
'capybara/poltergeist'
'phantomjs'

If I run rspec ./spec/features/my_tests_folder/, the first 2 tests in the folder always pass and the rest always end up with Capybara::Poltergeist::TimeoutError:.

If I run any of the tests in that folder individually, they ALL pass ALWAYS.

There are 7 test files total. They each have 1 feature with 1 scenario. All are js: true.

I have tried increasing :timeout in Capybara.register_driver and increasing default_max_wait_time in Capybara.configure. Neither changed the outcome.

I've also played around with Capybara.reset! after and before each test. It didn't seem to matter, either.

When I ran this with config.order = :random, sometimes 5 out of 7 had the erros, sometimes only 2 out of 7. But, there were always some errors and some passing. Also, every test was in the errors group at least once.

I'm running out of ideas. What could cause something like this?

UPDATE (to include Capybara and Poltergeist configs and example of a failing test):

Configs in rails_helper.rb:

Capybara.register_driver :poltergeist do |app|
  options = {
    :timeout => 90, # default is 30
    :js_errors => false,
    :phantomjs => Phantomjs.path,
    # :debug => true
  }
  Capybara::Poltergeist::Driver.new(app, options)
end

Capybara.register_driver :mechanize do |app|
  driver = Capybara::Mechanize::Driver.new(app)
  driver.configure do |agent|
    agent.user_agent_alias = 'Mac Safari'
  end

  driver
end

Capybara.configure do |config|
  config.run_server = false
  config.app_host = "http://my_vm_domain.com"
  config.javascript_driver = :poltergeist
  config.default_driver = :mechanize
  config.default_max_wait_time = 10 # default is 2
end

Example of failing test (not failing, but getting Capybara::Poltergeist::TimeoutError:):

require 'rails_helper'

feature 'agente visualiza estoques de um passeio', js: true do

  scenario 'com sucesso' do

    agente_log_in

    visit '/roteiro/show/723'

    find(:partial_href, 'new_passeio/723').click

    select 'Passeio Teste', from: 'passeio_produto'
    fill_in 'passeio_data', with: '11/11/2017'

    within('button#estoque_controls_0') do

      within('div#estoque_0_hora') do
        expect(page).to have_content('07:30')
      end

      within('span#estoque_0_vagas') do
        expect(page).to have_content('3')
      end

    end

    within('button#estoque_controls_1') do

      within('div#estoque_1_hora') do
        expect(page).to have_content('10:00')
      end

      within('span#estoque_1_vagas') do
        expect(page).to have_content('5')
      end

    end

  end

end

Code from agente_log_in.rb in support folder:

def agente_log_in

  Capybara.app_host = "http://my_vm_domain.com"

  visit '/usuario/logout'
  visit '/'

  fill_in 'data[AdmUsuario][usuario]', with: 'agente'
  fill_in 'data[AdmUsuario][senha]', with: 'pa$$w0rd'

  click_on 'Entrar'

end

Code for that :partial_href find:

module Selectors

  Capybara.add_selector(:partial_href) do
    xpath {|href| XPath.descendant[XPath.attr(:href).contains(href)] }
  end

end

Everything is fine with the other tests that are in the app's other folders. They're also fine if I run the tests in this folder individually. The problem only seems to happen when I run THIS specific folder as a whole.


Solution

  • After including the extra information requested by Thomas Walpole, I continued searching and studying possibilities.

    I eventually came across poltergeist's issue #781 on GitHub, which describes a situation very similar to mine, and eventually presents a wait_for_ajax solution.

    Before implementing it in my project, I read more about waiting for Ajax and found this post very helpful, too.

    In the end, I chose jasonfb's code from GitHub because it seemed more thorough and informative.

    It worked like a charm! My tests now pass consistently. I was even able to remove customization for :timeout and default_max_wait_time.

    The CakePHP app in question is very js heavy and the specific part that this folder tests is particularly full of Ajax requests.