Feature specs fail only on CircleCI or Codeship continuous integration services - selenium

My very basic feature specs are passing just fine locally but failing on CircleCI and Codeship. The tests that are failing:
require 'spec_helper'
describe 'Authentication' do
describe "sign in" do
it "is the landing page for non-authenticated users" do
user = create(:user)
visit root_path
expect( page ).to have_content 'LOG IN' # On sign-in page
fill_in 'Email', with: user.email
fill_in "Password", with: user.password
click_button 'Sign in'
expect( current_path ).to eq user_path(user)
end
end
describe 'registration' do
it "allows new users to register" do
visit root_path
click_link 'Sign up'
fill_in 'Email', with: 'myfake#email.com'
fill_in 'Password', with: 'password'
fill_in 'Password confirmation', with: 'password'
fill_in 'First name', with: 'John'
fill_in 'Last name', with: 'Doe'
click_button "Sign up"
expect( current_path ).to include '/users/'
expect( page ).to have_content "Welcome! You have signed up successfully."
end
end
end
The tests both fail on the first lines where they set expectations of the pages (expect( page ).to have_content "LOG IN" and click_link "Sign up", respectively), with errors suggesting the page HTML is completely blank:
expected to find text "LOG IN" in ""
I saved screenshots on CircleCI, and they indeed show a completely blank page.
Here's where it gets interesting. I tried debugging the problem by running/watching the specs on Circle using a VNC. When I a) set driver: :selenium for the tests, b) add a sleep 1 or two to the tests before testing the page expectations, and c) manually run the test after SSHing into their servers with the VNC, I can see the tests run in Selenium (they open a browser in the VNC) and they pass perfectly.
Outside of the VNC, however, the tests fail consistently in both CI servers. With or without tons of sleeps and driver: :selenium. Any ideas what could be causing this discrepancy between the regular CircleCI/Codeship servers and their VCN/my local test environment? I got in touch with the folks at CircleCI, but they're stumped for the moment.
If relevant, I'm running Ruby 2.2.0, Rails 4.2, Capybara 2.4.4, Capybara-Webkit 1.4.1, and Selenium-Webdriver 2.44.0
Some potentially relevant files:
spec_helper.rb
ENV["RAILS_ENV"] = "test"
require File.expand_path("../../config/environment", __FILE__)
require "rspec/rails"
require "shoulda/matchers"
require "webmock/rspec"
require 'vcr'
Dir[Rails.root.join("spec/support/**/*.rb")].each { |file| require file }
module Features
include Warden::Test::Helpers
Warden.test_mode!
def sign_in(user)
login_as(user, scope: :user)
end
end
module Controllers
# Pre-parse controller responses for easy access
def response_body
body = JSON.parse(response.body)
body.is_a?(Hash) ? body.to_sh : body.map(&:to_sh)
end
end
module Mock
def disable_webmock(&block)
WebMock.disable!
yield
WebMock.enable!
end
end
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = :expect
end
# Save a screenshot to CircleCI when a feature test fails
config.after(:each, :type => :feature) do |example|
if example.exception
artifact = save_page
puts "\"#{example.description}\" failed. Page saved to #{artifact}"
end
end
config.include Features, type: :feature
config.include Controllers, type: :controller
config.include Mock
config.include Formulaic::Dsl, type: :feature
config.infer_spec_type_from_file_location!
config.infer_base_class_for_anonymous_controllers = false
config.order = "random"
config.use_transactional_fixtures = false
end
RSpec::Matchers.define :hash_eq do |expected|
match do |actual|
actual.recursive_symbolize_keys == expected.recursive_symbolize_keys
end
end
VCR.configure do |c|
c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
c.hook_into :webmock
c.allow_http_connections_when_no_cassette = true
c.configure_rspec_metadata!
c.ignore_hosts '127.0.0.1', 'localhost:3000'
end
ActiveRecord::Migration.maintain_test_schema!
Capybara.javascript_driver = :webkit
if ENV['CIRCLE_ARTIFACTS']
Capybara.save_and_open_page_path = ENV['CIRCLE_ARTIFACTS']
end
WebMock.disable_net_connect!(allow_localhost: true)
database_cleaner.rb
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end

I can think of a couple of things to try:
If you want to get your specs to run headless, try using poltergeist rather than capybara-webkit. poltergeist has several advantages which I described here: https://stackoverflow.com/a/24108439/634576
Selenium might just be a distraction, but, if you want to get it to work, be sure that your CI environment has the right version of Firefox. Each version of selenium-webdriver seems to need a narrow range of versions of Firefox. On CircleCI, you can configure circle.yml to install a specific version of Firefox. Right now we use selenium-webdriver 2.46.2 and Firefox 39.0.3, installed with the following in circle.yml:
dependencies:
pre:
- sudo apt-get update; sudo apt-get install firefox=39.0.3+build2-0ubuntu0.12.04.1
I don't know about Codeship.

I have experienced instability of my Selenium tests on CircleCI until I came across this post https://discuss.circleci.com/t/selenium-tests-timing-out/7765/2
After adding:
machine:
environment:
DBUS_SESSION_BUS_ADDRESS: /dev/null
to my circle.yml, my tests have become stable.

Related

RSpec/Capybara Selenium Safari issue

The code below works with when running Chrome and Firefox. I am having issues with Safari using apple's new driver, however. Safari loads up, maximises window, but it will not input anything into the text fields. Please advise?
require 'capybara/rspec'
Capybara.configure do |config|
config.run_server = false
config.default_driver = :selenium
config.app_host = 'https://www.fake.com'
end
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app, browser: :safari)
end
Capybara.page.driver.browser.manage.window.maximize
Capybara.default_max_wait_time = 10
describe "Entering invalid credentials,", :type => :feature do
it "should prompt an error message." do
visit '/#/login'
#Code below does not work
fill_in 'Email', with: 'fake#email.com'
fill_in 'Password', with: 'fake'
click_button 'Log In'
end
end
: https://i.stack.imgur.com/tEG6f.png

Unable to use Capybara, Not sure where I am going wrong 'background' and 'it' etc is not working

Hi I am learning capybara, and i ve tried various answers in SO I am not able to proceed. I am trying to test a application with capybara. Visit is not working, errors out saying it needs to be within 'it' or example/executable block etc. but with below code , background and scenario etc is not working, execution is not going inside.
Results::
C:\Ruby223\bin\ruby.exe -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) C:/Users/xxx/RubymineProjects/xxx-app/spec/features/xxxxx.rb
"aaa"
Process finished with exit code 0
i dont want to mess up the Rails application, so I want a standalone file from where i can execute tests and then integrate with rails app with developers help.
require 'capybara/dsl'
require 'capybara'
require 'capybara/rspec'
require 'rspec'
feature "Signing in" do
p 'aaa'
background do
p 'aaa1'
Capybara.register_driver :selenium_chrome do |app|
Capybara::Selenium::Driver.new(app, :browser => :chrome)
end
Capybara.run_server = false
Capybara.current_driver = :selenium_chrome
Capybara.app_host = 'http://www.google.com'
end
scenario "Signing in with correct credentials" do
p 'aaa2'
visit '/q=?alkjaaa'
within("#session") do
fill_in 'email', with: 'user#example.com'
fill_in 'password', with: 'caplin'
end
click_button 'Signin'
expect(page).to have_content 'results'
end
given(:other_user) { User.make(email: 'other#example.com', password: 'rous') }
scenario "Signing in as another user" do
p 'aaa'
visit '/sessions/new'
within("#session") do
fill_in 'Email', with: other_user.email
fill_in 'Password', with: other_user.password
end
click_button 'Signin'
expect(page).to have_content 'Invalid email or password'
end
end
Running that file alone with ruby isn't going to do anything because all it does is define tests, it doesn't execute them. If you run that file with rspec then it will run the tests defined in the file.
rspec your_file.rb

Capybara actions not affecting test database

I have an app with users who can post and also vote for other posts. In testing with Capybara, I am having trouble getting the right actions to come through.
I have simplified my tests as much as possible to try to find the error easily, to no avail:
requests/users_spec.rb
require 'spec_helper'
describe "Users" do
before :all do
Warden.test_reset!
Warden.test_mode!
end
describe "when logged in, CAN" do
before :all do
User.all.map(&:destroy)
Post.all.map(&:destroy)
#user = User.create!(email: "foo#bar.baz",
username: "foobar",
password: "foobar",
password_confirmation: "foobar",
confirmed_at: Time.now - 1.minute)
#user2 = User.create!(email: "foo2#bar.baz",
username: "foobar2",
password: "foobar",
password_confirmation: "foobar",
confirmed_at: Time.now - 1.minute)
#post = Post.create!(
title: Faker::Lorem.sentence(5),
content: Faker::Lorem.sentence(25),
post_type: "temporary",
user_id: #user2.id
)
vote = LoggedUpvote.create!(user_id: #user2.id, post_id: #post.id)
login_as(#user, scope: :user)
end
it "create Upvotes", js: true do
count = Upvotes.all.count
visit post_path(#post.obfuscated_id)
page.find('.upvote').click
Upvotes.all.count.should eq(count + 1)
end
end
end
In my spec_helper.rb file I have:
Capybara.run_server = true
Capybara.server_port = 7000
Capybara.app_host = "http://localhost:#{Capybara.server_port}"
Capybara logs in just fine, navigates fine, and performs the actions fine, but the database record for the upvote is not created (despite showing visual confirmation that it has been created and that the right user is logged in).
The upvote is submitted through ajax, and a success response is shown on the screen, but no record is created in the database.
How can I get the record to create?
EDIT My spec_helper file looks like:
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'capybara/rspec'
require 'capybara/rails'
require 'rubygems'
require 'spork'
include Warden::Test::Helpers
# From http://stackoverflow.com/questions/8662554/how-to-use-the-test-database-with-capybara
Capybara.run_server = true
Capybara.server_port = 7000
Capybara.app_host = "http://localhost:#{Capybara.server_port}"
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
Spork.prefork do
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.infer_base_class_for_anonymous_controllers = false
config.order = "random" # From http://railscasts.com/episodes/413-fast-tests
config.include FactoryGirl::Syntax::Methods
config.treat_symbols_as_metadata_keys_with_true_values = true
config.filter_run focus: true
config.run_all_when_everything_filtered = true
config.filter_run_excluding :slow unless ENV["SLOW_SPECS"]
config.before(:all) { DeferredGarbageCollection.start }
config.after(:all) { DeferredGarbageCollection.reconsider }
config.before(:suite) { DatabaseCleaner.strategy = :truncation }
config.before(:each) { DatabaseCleaner.start }
config.after(:each) { DatabaseCleaner.clean }
end
end
Spork.each_run do
FactoryGirl.reload
end
I'm assuming that you are using a driver other than RackTest (based on your mention of ajax, you'd need some sort of javascript support). If so, you may not have setup Capybara correctly to share a database with the selenium driver. See this SO answer, this blog post or this part of the README for more details.
As it turns out, the database setup was fine, but Capybara was not waiting properly for the AJAX transaction to finish.
The solution was to add the following after the Upvote click and before the test assertion:
require "timeout"
Timeout.timeout(Capybara.default_wait_time) do
sleep(0.1) until Upvote.all.count == count + 1
end
And now everything works great.
Source: https://gist.github.com/jnicklas/d8da686061f0a59ffdf7

Request spec with Devise + Rspec2 + Spork/Guard

I have setup Rspec2 + Spork + Guard + Devise
My files are as follows
#spec_helper.rb
Spork.prefork do
#code
Dir[Rails.root.join('spec/support/**/*.rb')].each {|f| require f}
RSpec.configure do |config|
config.extend ControllerMacros, :type => :controller
end
end
Spork.each_run do
# This code will be run each time you run your specs.
FactoryGirl.reload
include ControllerMacros
end
#spec/support/controller_macros.rb
module ControllerMacros
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mapping[:user]
user = FactoryGirl.create(:user)
sign_in user
end
end
end
#spec/support/devise.rb
Spec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
in my request spec
#spec/features/documents_spec.rb
require 'spec_helper'
describe "Documents" do
login_user
describe "GET /documents" do
it "should display document name as sameera CV" do
#spec code
end
end
end
and when I run bundle exec guard, I get
1) Documents GET /documents should display document name as sameera CV
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `env' for nil:NilClass
# ./spec/support/controller_macros.rb:4:in `block in login_user'
So far I have done lots of fixes via google and nothing seems to be working, can someone help me :)
I'm on
rails 3.2.9
rspec 2.12.0
devise 2.2.3
any help would be greatly appreciated
Try changing #request.env["devise.mapping"] = Devise.mapping[:user] to request.env["devise.mapping"] = Devise.mapping[:user] in spec/support/controller_macros.rb
Here I'm answering my own question, and I was able to find a workaround for the question I asked.
Following are the steps I did
1) removed the controller_macros.rb and devise.rb from support directory
2) removed the ControllerMacros references from spec_helper.rb
3) Added the following code to
#spec/features/documents_spec.rb
before(:each) do
user = FactoryGirl.create(:user)
visit root_path
fill_in 'user_email', :with => user.email
fill_in 'user_password', :with => user.password
click_button 'Sign in'
end
I'm sure there should be a more elegant way (as describe in devise wiki), but this WORKS :)

Login Failure when Testing with Capybara, Rspec and Selenium in Rails 3.1

I added some confirmation dialog boxes for my Rails 3.1 application and, prior to that, their corresponding tests. Following the model of Railscast #257, I added ':js => true' to the test, added database_cleaner and modified the spec_helper.rb file accordingly.
When I run the test, Firefox launches, Capybara-Selenium fills in the fields the the appropriate username and a password, but log-in fails (i.e., "invalid username/password".) Other tests that do not have ':js => true' and also login, do still pass.
I would like to add more javascript to my application in the future and I am avoiding solutions that would hack Capybara to get this to work (e.g., click 'OK' on all dialogs.)
Any ideas what I might be missing? Fail that, any suggestions on how to debug this problem?
Thank you.
You should set use_transactional_fixtures = false for your seleniumtests.
This can be done in the spec_helper.rb with
config.use_transactional_fixtures = false
for all your tests.
Or do this for a single testcase:
describe 'testcase' , :type => :request do
self.use_transactional_fixtures = false
it 'your test', :js => :true do
testing...
end
end
This happens because selenium-tests access the database in a different way. With transactional fixtures enabled, selenium will work on an empty database -> your user does not exist and you cannot login.
For normal tests you should use transactional fixtures because your tests run much faster.
As per Avdi Grimm's post (features a detailed explanation):
Gemfile:
group :test do
gem 'database_cleaner'
end
spec_helper.rb:
config.use_transactional_fixtures = false
spec/support/database_cleaner.rb:
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
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
end
I had transactional fixtures disabled but adding the :js => true block to database_cleaner.rb did it for me.