1
votes

I'm quite desperate since moving our test suite from Minitest to RSpec. All the controller and model tests run fine so far, but since trying to port (formerly passing/working) feature tests like the following I ran into trouble...

feature 'Create place' do
  scenario 'create valid place as user' do
    login_as_user
    visit '/places/new'
    fill_in_valid_place_information
    click_button('Create Place')
    visit '/places'
    expect(page).to have_content('Any place', count: 1)
  end

  ...

  def fill_in_valid_place_information
      fill_in('place_name', with: 'Any place')
      fill_in('place_street', with: 'Magdalenenstr.')
      fill_in('place_house_number', with: '19')
      fill_in('place_postal_code', with: '10963')
      fill_in('place_city', with: 'Berlin')
      fill_in('place_email', with: '[email protected]')
      fill_in('place_homepage', with: 'http://schnapp.com')
      fill_in('place_phone', with: '03081763253')
  end
end

Unfortunately this does not lead to a DB commit which makes the test fail. It does not fail if i pry into the test and manually create the requested place. I tried different methods in order to trigger the button but nothing worked so far.

This is how my rails_helper.rb looks like:

ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
require 'capybara/rspec'
require 'capybara/rails'
require 'capybara/poltergeist'
require 'pry'

def validate_captcha
  fill_in 'captcha', with: SimpleCaptcha::SimpleCaptchaData.first.value
end

def login_as_user
  user = create :user, email: '[email protected]'
  visit 'login/'
  fill_in 'sessions_email', with: '[email protected]'
  fill_in 'sessions_password', with: 'secret'
  click_on 'Login'
end

Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

ActiveRecord::Migration.maintain_test_schema!

Capybara.register_driver :poltergeist do |app|
    Capybara::Poltergeist::Driver.new(app, phantomjs_options: ['--ignore-ssl-errors=true'])
end

Capybara.javascript_driver = :poltergeist

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

  config.before(:suite) do
    DatabaseCleaner.clean
  end

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

  config.before(:each, no_transaction: true) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each, js: true) do
    DatabaseCleaner.strategy = :truncation
  end

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

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

  config.include Capybara::DSL
  config.include Rails.application.routes.url_helpers
  config.fixture_path = "#{::Rails.root}/spec/fixtures"
  config.infer_spec_type_from_file_location!
  config.filter_rails_from_backtrace!
end

Does anyone have a clue about a possible cause? Gem versions:

  • capybara 2.12.0
  • rspec 3.5.0
  • rails 4.2.7.1

best and thanks, Andi

--- Update

I added fill_in_valid_place_information method

This is how the test fails with or without a Capybara JS driver enabled (shouldn't matter in case of this test as the feature does not use any JS). Unfortunately it doesn't give any real hints to work with...

1) Create place create valid place as user
     Failure/Error: expect(page).to have_content('Any place', count: 1)

       expected to find text "Any place" 1 time but found 0 times in "KIEZ KARTE Find places Here comes a list of all POIs currently available in our database. If you are looking for a specific location please enter parts of its descriptive features into the 'Search' field. Search: Name Postal code Categories No data available in table"

       Timeout reached while running a *waiting* Capybara finder...perhaps you wanted to return immediately? Use a non-waiting Capybara finder. More info: http://blog.codeship.com/faster-rails-tests?utm_source=gem_exception

--- Update 2

I found the issue which is not capyara-related. Actually I forgot to transfer a stub response for an API we're calling. Thanks everybody for participating in my struggle!

1
Can you post fill_in_valid_place_information method?Maxim Fedotov
Hey, thanks. I updated the answer to include the method and the failure message (which is not of much help)A. Neumann

1 Answers

2
votes

There are a number of potential issues in your test that could be causing what you are seeing, it would be easier to narrow down in the future if you included the actual error message(s) your test produces.

  1. Your scenarion/feature isn't tagged with :js metadata to activate using the Capybara driver. It's possible you've specified Capybara.default_driver somewhere, but if so then your DatabaseCleaner config is wrong

  2. Use the recommended DatabaseCleaner configuration from https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example . The driver name detection will work if you have specified Capybara.default_driver as mentioned in #1 and also with the :js/:driver metadata usage pattern. Additionally, the append_after/after difference is important to reduce test flakiness

  3. Your login_as_user method needs to verify the login has completed before returning. This is because click_on 'Login' can trigger asynchronously and return before the login actually occurs. This leads to the visit you call immediately following aborting the login, preventing the session cookie from being sent, and ending up with a non logged in user when you expected the user to be logged in. To fix this you need something like

    def login_as_user
      ...
      click_on 'Login'
      expect(page).to have_text('You are now logged in!') #whatever message is shown on successful login, or use have_css with some element on the page that only exists when a user is logged in (user menu, etc)
    end
    

    The same issue exists between click_button('Create Place') and visit '/places' where the visit can effectively cancel the effects of the button click