Skip to content

Instantly share code, notes, and snippets.

@jdickey
Last active December 18, 2015 00:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jdickey/5696686 to your computer and use it in GitHub Desktop.
Save jdickey/5696686 to your computer and use it in GitHub Desktop.
Daily WtF for 3 June 2013: Why do RSpec+Capybara(+Selenium) specs fail when executing the identical steps manually succeeds?
# From http://robots.thoughtbot.com/post/33771089985/
RSpec.configure do |config|
config.include Features::SessionHelpers, type: :feature
end
teabag /teabag Teabag::Engine
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
root / welcome#index
welcome_index GET /welcome/index(.:format) welcome#index
Routes for Teabag::Engine:
GET /fixtures/*filename(.:format) teabag/spec#fixtures
GET /:suite(.:format) teabag/spec#runner {:suite=>"default"}
root / teabag/spec#suites

SOLVED 3 June 2013 15:35 GMT/23.35 SGT

Thank you, +Drew Ulmer, my default DatabaseCleaner setup was indeed the culprit. Changing the strategy to :truncation fixed the problem. Of course, the idea that a database-cleanup utility could FUBAR your spec-automation tool in such a way that valid specs would fail, in your word, non-deterministically, is a Nietzsche incident. ("That which does not kill you makes you stronger.")

UPDATED 3 June 2013 11:08 GMT/19:08 SGT

Sort-of solved; using the exact same spec_helper.rb file as I was using on a different project that successfully deals with feature specs (but not JavaScript testing, yet) got me back to a known point. I've attached the earlier and current spec_helper.rb files for your spelunking pleasure.

Importantly, the spec at line 14 of user_signs_in_and_sees_name_greeting_spec.rb can either work or have the js: true option set; it can't (presently) have both.

I still don't know:

  • why enabling JS testing with either spec helper fails, even when no JS code is actually tested;
  • what changes really need to make to do authomated Script testing from RSpec; and thus
  • why the 'working' spec_helper.rb works and the 'non-working' one doesn't.

What am I missing here?

Very simple POC project with User model and feature spec as attached here. Feature spec fills in a (Devise-generated) login form and clicks the button. Zero rocket science here; we're at "RSpec Feature Specs with Capybara" 101, Exercise 1.

So how come

1. the form never gets the password value, and thus responds with expectable-under-the-circumstances `Username or password invalid`? Think the password isn't there? Uncomment lines 12 and 20 and see that the outputs from the `puts` calls match.
2. if you uncomment the `save_and_open_page` at line 22, it doesn't show the browser browser page *as Selenium saw it at that point*, but rather your *default* browser, at the (empty) login page, and oh yeah, the {Java,Coffee}Script files and stylesheets that are included in the "real" page, aren't?

I've been beating my head against this for an hour and all I have to show for my efforts is a headache. Any help appreciated; this has to be so basic I'm just not seeing it.

Attachments:

3. `spec/features/user_signs_in_and_sees_name_greeting_spec.rb`: **The spec demonstrating the confusion.**;
1. `app/models/user.rb`: a vestigial User class, with Devise bloviage included;
2. `spec/spec_helper.rb`: lines to note are 17-18, 33 and 69, where Capybara is wired in;
4. `spec/support/features.rb`: Configuration wiring for feature session helpers, per [Thoughtbot](http://robots.thoughtbot.com/post/33771089985/);
5. **Newly added** Output from `rake routes` command.

*Note that* through the "magic" of Github, these attachments do not appear in the order they were attached (or listed here).

Any ideas?
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
if ENV['RAILS_ENV'] == 'test'
require 'simplecov'
SimpleCov.start 'rails' do
add_group 'Decorators', 'app/decorators'
add_group 'Resources', 'app/resources'
add_filter '/vendor/'
end
end
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'rspec/http'
require 'capybara/rails'
require 'capybara/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
Capybara.register_driver :selenium do |app|
# Capybara::Selenium::Driver.new(app, browser: :chrome)
Capybara::Selenium::Driver.new app
end
Capybara.javascript_driver = :selenium
# Capybara.javascript_driver = :webkit
RSpec.configure do |config|
config.include Capybara
config.include Devise::TestHelpers, type: :controller
# config.extend ControllerMacros, type: :controller
config.include Devise::TestHelpers, type: :helper
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# 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.use_transactional_fixtures = true
config.use_transactional_fixtures = false
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
# Database_Cleaner setup per https://github.com/bmabey/database_cleaner
config.before(:suite) do
# Capybara.current_driver = :webkit
Capybara.current_driver = :selenium
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
if ENV['RAILS_ENV'] == 'test'
require 'simplecov'
SimpleCov.start 'rails' do
add_group 'Decorators', 'app/decorators'
add_group 'Resources', 'app/resources'
add_filter '/vendor/'
end
end
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'rspec/http'
require 'capybara/rails'
require 'capybara/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
# config.extend ControllerMacros, type: :controller
config.include Devise::TestHelpers, type: :helper
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# 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.use_transactional_fixtures = true
config.use_transactional_fixtures = false
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
# Database_Cleaner setup per https://github.com/bmabey/database_cleaner
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
if ENV['RAILS_ENV'] == 'test'
require 'simplecov'
SimpleCov.start 'rails' do
add_group 'Decorators', 'app/decorators'
add_group 'Resources', 'app/resources'
add_filter '/vendor/'
end
end
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'rspec/http'
require 'capybara/rails'
require 'capybara/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
Capybara.register_driver :selenium do |app|
# Capybara::Selenium::Driver.new(app, browser: :chrome)
Capybara::Selenium::Driver.new app
end
Capybara.javascript_driver = :selenium
# Capybara.javascript_driver = :webkit
RSpec.configure do |config|
config.include Capybara::DSL
config.include Devise::TestHelpers, type: :controller
# config.extend ControllerMacros, type: :controller
config.include Devise::TestHelpers, type: :helper
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# 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.use_transactional_fixtures = true
config.use_transactional_fixtures = false
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
# Database_Cleaner setup per https://github.com/bmabey/database_cleaner
config.before(:suite) do
Capybara.current_driver = :selenium
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
# Simple/simplistic User model. Doesn't yet relate to anything.
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
attr_accessible :bio, :email, :name
validates_presence_of :name
validates_presence_of :email
validates_presence_of :password, on: :create
end
require 'spec_helper'
describe 'Registered user at home page', type: :feature do
def welcome_message_for user_name
"Welcome, #{user_name}!"
end
before :each do
@user = FactoryGirl.create :user
# puts "***** #{@user.password.to_s}"
end
it 'can sign in', js: true do
visit root_path
click_link 'Welcome, Guest!'
click_link 'Login'
fill_in 'user_email', with: @user.email
# puts "+++++ #{@user.password}"
fill_in 'user_password', with: @user.password
# save_and_open_page
click_button 'Sign in'
page.should have_content welcome_message_for(@user.name)
end
end # describe 'Registered user at home page'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment