RSpec use_transactional_fixtures=false not working - ruby-on-rails

Setting use_transactional_fixtures=false in my spec_helper.rb file, though when I look at the output of my test log, it appears a transaction is still being used? Why is that the case and how do I eliminate the transaction?
rails_helper.rb...
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = false
config.infer_spec_type_from_file_location!
config.include FactoryGirl::Syntax::Methods
end
spec_helper.rb...
require 'devise'
require "paperclip/matchers"
require 'simplecov'
require 'database_cleaner'
require 'capybara/rspec'
SimpleCov.start 'rails'
module SphinxHelpers
def index
ThinkingSphinx::Test.index
# Wait for Sphinx to finish loading in the new index files.
sleep 0.25 until index_finished?
end
def index_finished?
Dir[Rails.root.join(ThinkingSphinx::Test.config.indices_location, '*.{new,tmp}*')].empty?
end
end
RSpec.configure do |config|
config.include SphinxHelpers
config.before(:suite) do
# Ensure sphinx directories exist for the test environment
ThinkingSphinx::Test.init
# Configure and start Sphinx, and automatically
# stop Sphinx at the end of the test suite.
ThinkingSphinx::Test.start_with_autostop
end
config.before(:each) do |example|
index
end
config.include Paperclip::Shoulda::Matchers
config.include Devise::TestHelpers, :type => :controller
config.raise_errors_for_deprecations!
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
end
RSpec::Matchers.define :accept_nested_attributes_for do |association|
match do |model|
#model = model
#nested_att_present = model.respond_to?("#{association}_attributes=".to_sym)
if #nested_att_present && #reject
model.send("#{association}_attributes=".to_sym,[#reject])
#reject_success = model.send("#{association}").empty?
end
if #nested_att_present && #accept
model.send("#{association}_attributes=".to_sym,[#accept])
#accept_success = ! (model.send("#{association}").empty?)
end
#nested_att_present && ( #reject.nil? || #reject_success ) && ( #accept.nil? || #accept_success )
end
failure_message_for_should do
messages = []
messages << "expected #{#model.class} to accept nested attributes for #{association}" unless #nested_att_present
messages << "expected #{#model.class} to reject values #{#reject.inspect} for association #{association}" unless #reject_success
messages << "expected #{#model.class} to accept values #{#accept.inspect} for association #{association}" unless #accept_success
messages.join(", ")
end
description do
desc = "accept nested attributes for #{expected}"
if #reject
desc << ", but reject if attributes are #{#reject.inspect}"
end
end
chain :but_reject do |reject|
#reject = reject
end
chain :and_accept do |accept|
#accept = accept
end
end
a spec that displays the problem....
require 'rails_helper'
RSpec.describe "The homepage", :type => :feature do
it "displays articles" do
article = create(:article)
visit "/"
assert page.has_css?(".article")
end
end
the test log output when running the spec (note the transaction)...
(0.2ms) ALTER TABLE "annotations" DISABLE TRIGGER ALL;ALTER TABLE "categories" DISABLE TRIGGER ALL;ALTER TABLE "schema_migrations" DISABLE TRIGGER ALL;ALTER TABLE "articles" DISABLE TRIGGER ALL;ALTER TABLE "comments" DISABLE TRIGGER ALL;ALTER TABLE "contents" DISABLE TRIGGER ALL;ALTER TABLE "galleries" DISABLE TRIGGER ALL;ALTER TABLE "gallery_images" DISABLE TRIGGER ALL;ALTER TABLE "users" DISABLE TRIGGER ALL
(13.5ms) TRUNCATE TABLE "annotations", "categories", "articles", "comments", "contents", "galleries", "gallery_images", "users" RESTART IDENTITY CASCADE;
(0.7ms) ALTER TABLE "annotations" ENABLE TRIGGER ALL;ALTER TABLE "categories" ENABLE TRIGGER ALL;ALTER TABLE "schema_migrations" ENABLE TRIGGER ALL;ALTER TABLE "articles" ENABLE TRIGGER ALL;ALTER TABLE "comments" ENABLE TRIGGER ALL;ALTER TABLE "contents" ENABLE TRIGGER ALL;ALTER TABLE "galleries" ENABLE TRIGGER ALL;ALTER TABLE "gallery_images" ENABLE TRIGGER ALL;ALTER TABLE "users" ENABLE TRIGGER ALL
ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations".* FROM "schema_migrations"
(0.6ms) ALTER TABLE "annotations" DISABLE TRIGGER ALL;ALTER TABLE "categories" DISABLE TRIGGER ALL;ALTER TABLE "schema_migrations" DISABLE TRIGGER ALL;ALTER TABLE "articles" DISABLE TRIGGER ALL;ALTER TABLE "comments" DISABLE TRIGGER ALL;ALTER TABLE "contents" DISABLE TRIGGER ALL;ALTER TABLE "galleries" DISABLE TRIGGER ALL;ALTER TABLE "gallery_images" DISABLE TRIGGER ALL;ALTER TABLE "users" DISABLE TRIGGER ALL
(1.0ms) select table_name from information_schema.views where table_schema = 'site_test'
(23.8ms) TRUNCATE TABLE "annotations", "categories", "articles", "comments", "contents", "galleries", "gallery_images", "users" RESTART IDENTITY CASCADE;
(0.7ms) ALTER TABLE "annotations" ENABLE TRIGGER ALL;ALTER TABLE "categories" ENABLE TRIGGER ALL;ALTER TABLE "schema_migrations" ENABLE TRIGGER ALL;ALTER TABLE "articles" ENABLE TRIGGER ALL;ALTER TABLE "comments" ENABLE TRIGGER ALL;ALTER TABLE "contents" ENABLE TRIGGER ALL;ALTER TABLE "galleries" ENABLE TRIGGER ALL;ALTER TABLE "gallery_images" ENABLE TRIGGER ALL;ALTER TABLE "users" ENABLE TRIGGER ALL
(0.1ms) BEGIN
(0.1ms) COMMIT
(0.1ms) BEGIN
(0.1ms) SAVEPOINT active_record_1
User Exists (0.5ms) SELECT 1 AS one FROM "users" WHERE "users"."username" = 'testuser' LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'testuser#miscia.net' LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'testuser#miscia.net' LIMIT 1
SQL (0.7ms) INSERT INTO "users" ("created_at", "email", "encrypted_password", "updated_at", "username") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["created_at", "2015-03-08 20:48:58.017027"], ["email", "testuser#miscia.net"], ["encrypted_password", "$2a$04$vHQdcMEuRC2mdrNebemS5e9zMOUaloIhcIBEHlu6z7ms8Rh2NJ0F."], ["updated_at", "2015-03-08 20:48:58.017027"], ["username", "testuser"]]
(0.2ms) RELEASE SAVEPOINT active_record_1
Command :: file -b --mime '/var/folders/px/vlftvj1j43j7369cy2_sz_j40000gn/T/aacb8db341826e828273a80db5d60d5220150308-5197-hsarwm.png'
Command :: identify -format '%wx%h,%[exif:orientation]' '/var/folders/px/vlftvj1j43j7369cy2_sz_j40000gn/T/aacb8db341826e828273a80db5d60d5220150308-5197-hlhno1.png[0]' 2>/dev/null
Command :: identify -format %m '/var/folders/px/vlftvj1j43j7369cy2_sz_j40000gn/T/aacb8db341826e828273a80db5d60d5220150308-5197-hlhno1.png[0]'
Command :: convert '/var/folders/px/vlftvj1j43j7369cy2_sz_j40000gn/T/aacb8db341826e828273a80db5d60d5220150308-5197-hlhno1.png[0]' -auto-orient -resize "100%" '/var/folders/px/vlftvj1j43j7369cy2_sz_j40000gn/T/aacb8db341826e828273a80db5d60d5220150308-5197-hlhno120150308-5197-1j86yzw'
Command :: file -b --mime '/var/folders/px/vlftvj1j43j7369cy2_sz_j40000gn/T/aacb8db341826e828273a80db5d60d5220150308-5197-hlhno120150308-5197-1j86yzw'
(0.1ms) SAVEPOINT active_record_1
Command :: file -b --mime '/var/folders/px/vlftvj1j43j7369cy2_sz_j40000gn/T/aacb8db341826e828273a80db5d60d5220150308-5197-h4xfii.png'
Article Exists (0.5ms) SELECT 1 AS one FROM "articles" WHERE "articles"."title" = 'Article Title' LIMIT 1
SQL (6.4ms) INSERT INTO "articles" ("body", "created_at", "description", "header_one", "header_two", "photo_content_type", "photo_file_name", "photo_file_size", "photo_updated_at", "posted_at", "title", "updated_at", "url", "user_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING "id" [["body", "This is the article body."], ["created_at", "2015-03-08 20:48:58.218394"], ["description", "This is a test article!"], ["header_one", "Article Header One"], ["header_two", "Article Header Two"], ["photo_content_type", "image/png"], ["photo_file_name", "test_image.png"], ["photo_file_size", 96884], ["photo_updated_at", "2015-03-08 20:48:58.036313"], ["posted_at", "2015-03-08 20:48:51.398651"], ["title", "Article Title"], ["updated_at", "2015-03-08 20:48:58.218394"], ["url", "http://www.testurl.com"], ["user_id", 1]]
(0.2ms) RELEASE SAVEPOINT active_record_1
Started GET "/" for 127.0.0.1 at 2015-03-08 16:48:58 -0400
Processing by SiteController#index as HTML
Sphinx Query (9.3ms) SELECT * FROM `article_core` WHERE `sphinx_deleted` = 0 ORDER BY `created_at` DESC LIMIT 0, 5
Sphinx Found 0 results
Rendered articles/_pagination.html.erb (0.7ms)
Rendered articles/_list.html.erb (13.0ms)
Category Load (0.3ms) SELECT "categories".* FROM "categories"
Rendered site/homepage/_filters.html.erb (1.3ms)
Rendered site/homepage/_search.html.erb (57.1ms)
Rendered site/homepage/_twitter.html.erb (0.5ms)
Rendered site/homepage/_sidebar.html.erb (61.2ms)
Rendered site/index.html.erb within layouts/application (76.3ms)
Rendered site/_head.html.erb (19.8ms)
Rendered site/homepage/_social_media.html.erb (0.5ms)
Rendered site/homepage/_social_media.html.erb (0.1ms)
Rendered site/homepage/_social_media.html.erb (0.1ms)
Rendered site/homepage/_social_media.html.erb (0.1ms)
Rendered site/homepage/_menu.html.erb (8.0ms)
Content Load (0.4ms) SELECT "contents".* FROM "contents" WHERE "contents"."name_slug" = 'footer_left' ORDER BY "contents"."id" ASC LIMIT 1
Content Load (0.3ms) SELECT "contents".* FROM "contents" WHERE "contents"."name_slug" = 'footer_middle' ORDER BY "contents"."id" ASC LIMIT 1
Rendered site/_footer.html.erb (8.6ms)
Rendered site/_ga.html.erb (0.4ms)
Completed 200 OK in 128ms (Views: 116.4ms | ActiveRecord: 2.2ms)
(0.2ms) ROLLBACK

When you set config.use_transactional_fixtures = false you are telling RSpec to not bother cleaning the database each time it starts a new example. Sometimes I set this to false because I instead use database_cleaner (GitHub) to handle it.
So, based on your logs, I believe RSpec is doing exactly what it is supposed to be doing.
You can read about this setting in the RSpec manual

Related

RSpec + Poltergeist fails when setting authenticity_token

I am trying to test a feature in my Rails app using RSpec + Polgergeist.
My feature spec is very basic right now:
RSpec.feature 'Listing owners can create new listings' do
let(:owner) { create(:user, :owner) }
before do
login_as owner
# I've also tried this with as recommended by Devise when using Capybara-Webkit:
# login_as(user, scope: :user, run_callbacks: false)
visit new_listing_path
end
scenario 'successfully', js: true do
fill_in 'Field 1', with: 'Example'
click_link 'Create'
# expectations here...
end
end
I have the following in my rails_helper.rb
require 'capybara/poltergeist'
RSpec.configure do |config|
# ...
config.include Warden::Test::Helpers, type: :feature
config.after(type: :feature) { Warden.test_reset! }
# ...
end
and in a support/poltergeist.rb file
RSpec.configure do |config|
Capybara.javascript_driver = :poltergeist
# Increase timeout in case asset compilation
# takes longer than anticipated.
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, {timeout: 60})
end
end
The precise location that is failing is this, where I set the CSRF token using Vue.js:
import Vue from 'vue/dist/vue.esm'
import VueResource from 'vue-resource'
Vue.use(VueResource)
document.addEventListener('DOMContentLoaded', () => {
if(document.getElementById('listing-multistep') !== null) {
Vue.http.headers.common['X-CSRF-Token'] = document.querySelector('input[name="authenticity_token"]').getAttribute('value');
var listingForm = document.getElementById('listing_form');
var listing = JSON.parse(listingForm.dataset.listing);
// do magic....
}
});
The authenticity token is set from the Rails form partial, _form.html.erb:
<%= form_for(
listing,
html: { multipart: true, id: 'listing_form',
data: {
listing: listing.to_json(except: [:user_id, :created_at, :updated_at])
}
}) do |f| %>
<fieldset class="listing-step" v-show="activeStep === 0">
<%= render 'listings/form/basics', f: f, listing: listing %>
</fieldset>
<fieldset class="listing-step" v-show="activeStep === 1">
<%= render 'listings/form/location', f: f, listing: listing %>
</fieldset>
<fieldset class="listing-step" v-show="activeStep === 2">
<%= render 'listings/form/amenities', f: f, listing: listing %>
</fieldset>
<fieldset class="listing-step" v-show="activeStep === 3">
<%= render 'listings/form/description', f: f, listing: listing %>
</fieldset>
<% end %>
Setting the CSRF token this way seems to work in development, but when I run the spec, I am seeing the following error:
Failure/Error: visit new_listing_path
Capybara::Poltergeist::JavascriptError:
One or more errors were raised in the Javascript code on the page. If you don't care about these errors, you can ignore them by setting js_errors: false in your Poltergeist configuration (see documentation for details).
TypeError: null is not an object (evaluating 'document.querySelector('input[name="authenticity_token"]').getAttribute')
TypeError: null is not an object (evaluating 'document.querySelector('input[name="authenticity_token"]').getAttribute')
at http://127.0.0.1:54450/packs-test/dashboard-ca7eeed2cc4b22399ade.js:13086
All I can think of is that poltergeist isn't waiting for the DOM to load fully, but that would be strange because I have explicitly written the vue code within document.addEventListener('DOMContentLoaded', () => {
As an aside, I also have a support/database_cleaner.rb file with the following contents:
RSpec.configure do |conf|
conf.before(:suite) do
DatabaseCleaner.clean_with :truncation
end
conf.before(:each) do
DatabaseCleaner.strategy = :transaction
end
conf.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
end
conf.before(:each) do
DatabaseCleaner.start
end
conf.after(:each) do
DatabaseCleaner.clean
end
end
Any idea what may be causing the aforementioned error? Any help is much appreciated!
Thanks in advance
UPDATE
Here is a copy of the test.log file that is generated when I run the spec:
(1.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
(0.2ms) BEGIN
(2.1ms) ALTER TABLE "schema_migrations" DISABLE TRIGGER ALL;ALTER TABLE "ar_internal_metadata" DISABLE TRIGGER ALL;ALTER TABLE "subscriptions" DISABLE TRIGGER ALL;ALTER TABLE "listings" DISABLE TRIGGER ALL;ALTER TABLE "advertisements" DISABLE TRIGGER ALL;ALTER TABLE "chatroom_users" DISABLE TRIGGER ALL;ALTER TABLE "chatrooms" DISABLE TRIGGER ALL;ALTER TABLE "messages" DISABLE TRIGGER ALL;ALTER TABLE "pictures" DISABLE TRIGGER ALL;ALTER TABLE "friendly_id_slugs" DISABLE TRIGGER ALL;ALTER TABLE "contact_messages" DISABLE TRIGGER ALL;ALTER TABLE "users" DISABLE TRIGGER ALL
(0.7ms) COMMIT
(3.9ms) SELECT schemaname || '.' || tablename
FROM pg_tables
WHERE
tablename !~ '_prt_' AND
tablename <> 'schema_migrations' AND tablename <> 'ar_internal_metadata' AND
schemaname = ANY (current_schemas(false))
(2.5ms) select table_name from information_schema.views where table_schema = 'salayo_test'
(48.9ms) TRUNCATE TABLE "public"."subscriptions", "public"."listings", "public"."advertisements", "public"."chatroom_users", "public"."chatrooms", "public"."messages", "public"."pictures", "public"."friendly_id_slugs", "public"."contact_messages", "public"."users" RESTART IDENTITY CASCADE;
(1.3ms) BEGIN
(1.7ms) ALTER TABLE "schema_migrations" ENABLE TRIGGER ALL;ALTER TABLE "ar_internal_metadata" ENABLE TRIGGER ALL;ALTER TABLE "subscriptions" ENABLE TRIGGER ALL;ALTER TABLE "listings" ENABLE TRIGGER ALL;ALTER TABLE "advertisements" ENABLE TRIGGER ALL;ALTER TABLE "chatroom_users" ENABLE TRIGGER ALL;ALTER TABLE "chatrooms" ENABLE TRIGGER ALL;ALTER TABLE "messages" ENABLE TRIGGER ALL;ALTER TABLE "pictures" ENABLE TRIGGER ALL;ALTER TABLE "friendly_id_slugs" ENABLE TRIGGER ALL;ALTER TABLE "contact_messages" ENABLE TRIGGER ALL;ALTER TABLE "users" ENABLE TRIGGER ALL
(0.6ms) COMMIT
(0.3ms) BEGIN
User Exists (2.0ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2 [["email", "dianna_kilback#okeefemccullough.org"], ["LIMIT", 1]]
SQL (1.1ms) INSERT INTO "users" ("first_name", "last_name", "email", "encrypted_password", "created_at", "updated_at", "role") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["first_name", "Hermann"], ["last_name", "VonRueden"], ["email", "dianna_kilback#okeefemccullough.org"], ["encrypted_password", "$2a$04$sSAdYthaHRhqjUqaing/weltoDcyHyR5Fyr2Pw/8xOtvz4mMPwWYm"], ["created_at", "2018-04-01 05:32:07.693349"], ["updated_at", "2018-04-01 05:32:07.693349"], ["role", 2]]
(0.6ms) COMMIT
Started GET "/en/listings/new" for 127.0.0.1 at 2018-04-01 14:32:09 +0900
(0.2ms) BEGIN
SQL (2.5ms) UPDATE "users" SET "sign_in_count" = $1, "current_sign_in_at" = $2, "last_sign_in_at" = $3, "current_sign_in_ip" = $4, "last_sign_in_ip" = $5, "updated_at" = $6 WHERE "users"."id" = $7 [["sign_in_count", 1], ["current_sign_in_at", "2018-04-01 05:32:09.833321"], ["last_sign_in_at", "2018-04-01 05:32:09.833321"], ["current_sign_in_ip", "127.0.0.1/32"], ["last_sign_in_ip", "127.0.0.1/32"], ["updated_at", "2018-04-01 05:32:09.866550"], ["id", 1]]
(0.6ms) COMMIT
Processing by ListingsController#new as HTML
Parameters: {"locale"=>"en"}
Rendering listings/new.html.erb within layouts/dashboard
Rendered listings/_prev_next_buttons.html.erb (3.6ms)
Rendered listings/form/_basics.html.erb (30.6ms)
Rendered listings/form/_location.html.erb (2.9ms)
Rendered listings/form/_amenities.html.erb (0.5ms)
Rendered listings/form/_description.html.erb (3.5ms)
Rendered listings/_form.html.erb (79.4ms)
Rendered listings/new.html.erb within layouts/dashboard (127.9ms)
Rendered common/_meta_tags.html.erb (1.2ms)
Rendered dashboard/_sidebar.html.erb (23.4ms)
Rendered dashboard/_topbar.html.erb (4.7ms)
Rendered common/_notices.html.erb (2.0ms)
Rendered common/_footer.html.erb (4.9ms)
Completed 200 OK in 980ms (Views: 877.4ms | ActiveRecord: 19.7ms)
Started GET "/assets/application-a2d7fced50ec51954f27ed1fab4792ab0cd3b9b88ff496fc07bd2489660a7c42.css" for 127.0.0.1 at 2018-04-01 14:32:10 +0900
Started GET "/assets/application-e7598b8619f2ba6c7b08ce9a5471f5e4b5223c384a09f8826ae19a864a9bc6b4.js" for 127.0.0.1 at 2018-04-01 14:32:10 +0900
Started GET "/cable" for 127.0.0.1 at 2018-04-01 14:32:11 +0900
Started GET "/assets/bg_logo-db2dd881e08b614d8971e623eb0a14df67c93a5615c04ec2d7c2967893d44b2c.svg" for 127.0.0.1 at 2018-04-01 14:32:11 +0900
Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2018-04-01 14:32:11 +0900
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
Started GET "/assets/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff" for 127.0.0.1 at 2018-04-01 14:32:11 +0900
(0.3ms) BEGIN
(1.6ms) ALTER TABLE "schema_migrations" DISABLE TRIGGER ALL;ALTER TABLE "ar_internal_metadata" DISABLE TRIGGER ALL;ALTER TABLE "subscriptions" DISABLE TRIGGER ALL;ALTER TABLE "listings" DISABLE TRIGGER ALL;ALTER TABLE "advertisements" DISABLE TRIGGER ALL;ALTER TABLE "chatroom_users" DISABLE TRIGGER ALL;ALTER TABLE "chatrooms" DISABLE TRIGGER ALL;ALTER TABLE "messages" DISABLE TRIGGER ALL;ALTER TABLE "pictures" DISABLE TRIGGER ALL;ALTER TABLE "friendly_id_slugs" DISABLE TRIGGER ALL;ALTER TABLE "contact_messages" DISABLE TRIGGER ALL;ALTER TABLE "users" DISABLE TRIGGER ALL
(0.5ms) COMMIT
(56.7ms) TRUNCATE TABLE "public"."subscriptions", "public"."listings", "public"."advertisements", "public"."chatroom_users", "public"."chatrooms", "public"."messages", "public"."pictures", "public"."friendly_id_slugs", "public"."contact_messages", "public"."users" RESTART IDENTITY CASCADE;
(1.7ms) BEGIN
(2.7ms) ALTER TABLE "schema_migrations" ENABLE TRIGGER ALL;ALTER TABLE "ar_internal_metadata" ENABLE TRIGGER ALL;ALTER TABLE "subscriptions" ENABLE TRIGGER ALL;ALTER TABLE "listings" ENABLE TRIGGER ALL;ALTER TABLE "advertisements" ENABLE TRIGGER ALL;ALTER TABLE "chatroom_users" ENABLE TRIGGER ALL;ALTER TABLE "chatrooms" ENABLE TRIGGER ALL;ALTER TABLE "messages" ENABLE TRIGGER ALL;ALTER TABLE "pictures" ENABLE TRIGGER ALL;ALTER TABLE "friendly_id_slugs" ENABLE TRIGGER ALL;ALTER TABLE "contact_messages" ENABLE TRIGGER ALL;ALTER TABLE "users" ENABLE TRIGGER ALL
(0.5ms) COMMIT

Rspec's expect change count not working

Here I'm testing the changes in current_user.messages.count after the current user sends a valid message. Here's my code:
spec
scenario 'adds to their messages', js: true do
expect { find('#message_content').send_keys(:enter) }.to \
change(current_user.messages, :count).by(1)
end
test.log
# ...
ConversationChannel is transmitting the subscription confirmation
ConversationChannel is streaming from conversation_channel_1
(0.6ms) SELECT COUNT(*) FROM "messages" WHERE "messages"."user_id" = $1 [["user_id", 1]]
ConversationChannel#send_message({"content"=>"foobar\n", "conversation_id"=>"1"})
(0.3ms) BEGIN
(0.9ms) SELECT COUNT(*) FROM "messages" WHERE "messages"."user_id" = $1 [["user_id", 1]]
Conversation Load (1.6ms) SELECT "conversations".* FROM "conversations" WHERE "conversations"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
(0.7ms) SELECT "users"."id" FROM "users" INNER JOIN "user_conversations" ON "users"."id" = "user_conversations"."user_id" WHERE "user_conversations"."conversation_id" = $1 [["conversation_id", 1]]
SQL (1.0ms) INSERT INTO "messages" ("content", "user_id", "conversation_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["content", "foobar\n"], ["user_id", 1], ["conversation_id", 1], ["created_at", "2018-01-29 11:27:13.095277"], ["updated_at", "2018-01-29 11:27:13.095277"]]
Finished "/cable/" [WebSocket] for 127.0.0.1 at 2018-01-29 19:27:13 +0800
ConversationChannel stopped streaming from conversation_channel_1
(0.2ms) BEGIN
(58.8ms) COMMIT
(16.7ms) ALTER TABLE "schema_migrations" DISABLE TRIGGER ALL;ALTER TABLE "ar_internal_metadata" DISABLE TRIGGER ALL;ALTER TABLE "conversations" DISABLE TRIGGER ALL;ALTER TABLE "messages" DISABLE TRIGGER ALL;ALTER TABLE "user_conversations" DISABLE TRIGGER ALL;ALTER TABLE "users" DISABLE TRIGGER ALL
Rendered messages/_message.html.erb (0.6ms)
[ActionCable] Broadcasting to conversation_channel_1: {:message=>"<p>User 1: foobar\n</p>\n"}
# ...
The spec fails expected #count to have changed by 1, but was changed by 0 even though in the log shows INSERT INTO actually happen.
This doesn't work because you're not waiting long enough for the message addition to actually occur. send_keys returns as soon as the browser has been sent the key event, but knows nothing at all about any request/action triggered by that key press in the browser. This is why direct DB access tests are generally a bad idea in feature/system tests (which should generally just test user visible changes/interactions) and make more sense as request or controller.
That being said you could fix this by just sleeping after sending the key, but a better solution is to use one of the Capybara provided matchers (have waiting/retrying behavior) to synchronize the test.
scenario 'adds to their messages', js: true do
expect do
find('#message_content').send_keys(:enter) }
expect(page).to have_css(...) # check for whatever visible change on the page indicates the action triggered by send_keys has completed
end.to change { current_user.reload.messages.count }.by(1)
end
Note: This test is also very simple for a feature test. It's okay to have multiple expectations in a feature test since it's really meant to test a whole user interaction with a specific feature of your app. You might want to look at combining this test with other tests of the same part of your app.
Try to write :
change{current_user.messages, :count}.by(1)
with {}

Cannot Login User when Using Selenium with Rails/RSpec

I am running tests that starts by logging in a user using the login form. It successfully opens Firefox, navigates to the login form and fills in the fields, but when it clicks the 'Login' button, it hangs indefinitely. When I quit Firefox the test that was running fails, but I am not getting any additional error message.
Any idea what I am doing wrong? This is driving me crazy and preventing me from testing a big portion of my app, any help would be much appreciated! Thanks!
Here is some additional info:
Rails 4.2.0
Ruby 2.2.4
Capybara 2.6.2
Selenium-Webdriver 2.53.0
Firefox 46.0.1
Using Capybara with RSpec
Capybara.javascript_driver = :selenium
/spec_helper.rb
require 'rubygems'
require 'spork'
#uncomment the following line to use spork with the debugger
#require 'spork/ext/ruby-debug'
Spork.prefork do
# Loading more in this block will cause your tests to run faster. However,
# if you change any configuration or code from libraries loaded here, you'll
# need to restart spork for it take effect.
require 'simplecov'
SimpleCov.start 'rails'
require 'capybara/rspec'
require 'aasm/rspec'
RSpec.configure do |config|
config.include Capybara::DSL
def test_sign_in(user)
# helper method to sign in the passed-in user
visit new_user_session_path
within ('#user-login-non-modal') do
within(".user-login") do
fill_in 'Email', with: user.email
fill_in 'Password', with: 'foobar11'
click_button 'Sign in'
end
end
end
def test_partner_sign_in(partner)
# helper method to sign in the passed-in partner
visit new_partner_session_path
within('#partner-login-non-modal') do
within(".partner-login") do
fill_in 'Email', with: partner.email
fill_in 'Password', with: 'foobar11'
click_button 'Sign in'
end
end
end
# configure database cleaner
config.before(:suite) do
DatabaseCleaner.start
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
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
# Many RSpec users commonly either run the entire suite or an individual
# file, and it's useful to allow more verbose output when running an
# individual spec file.
# if config.files_to_run.one?
# Use the documentation formatter for detailed output,
# unless a formatter has already been configured
# (e.g. via a command-line flag).
# config.default_formatter = 'doc'
# end
end
end
Spork.each_run do
# This code will be run each time you run your specs.
end
/rails_helper.rb
# This file is copied to spec/ when you run 'rails generate
rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'devise'
require 'controller_macros'
require 'byebug'
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.include Devise::TestHelpers, :type => :controller
config.include Rails.application.routes.url_helpers
config.extend ControllerMacros, :type => :controller
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
end
/test.rb
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
config.eager_load = false
# Configure static asset server for tests with Cache-Control for performance.
config.serve_static_files = true
config.static_cache_control = 'public, max-age=3600'
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# For Devise
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end
.rspec
--color
--require spec_helper
--drb
Edit:
user_pages_spec.rb
describe "show page" do
before do
# #user = FactoryGirl.create(:user)
#user = User.invite!(:email => "test_user#example.com", :skip_invitation => true)
#user.accept_invitation!
#user.password = "foobar11"
#user.first_name = "John"
#user.last_name = "Smith"
#user.save
#car1 = FactoryGirl.create(:car, user: #user)
#car2 = FactoryGirl.create(:car, user: #user)
#tomorrow = Time.now + 24*60*60
#earlier_today = Time.now - 30
#app_in_future1 = FactoryGirl.create(:appointment, car: #car1, garage: #car1.garage, pickuptime: #tomorrow)
#app_in_future2 = FactoryGirl.create(:appointment, car: #car1, garage: #car1.garage, pickuptime: #tomorrow + 24*60*60)
#app_in_past = FactoryGirl.build(:appointment, car: #car1, garage: #car1.garage, pickuptime: #earlier_today)
#app_in_past.save(validate: false)
different_pickup_time = #tomorrow + 60*60
#different_user = FactoryGirl.create(:user)
#car_different_user = FactoryGirl.create(:car, make: "diff_make", user: #different_user)
#app_different_user = FactoryGirl.create(:appointment, car: #car_different_user, garage: #car_different_user.garage, pickuptime: different_pickup_time)
test_sign_in(#user)
end
describe "adding an appointment to a car", js:true do
context "when the appointment is in the future" do
it "should increment the number of the car's appointments" do
expect do
within(".create-appt-row-#{#car1.id}") do
click_button 'Add Appointment'
fill_in 'appointment_pickuptime', with: "12/07/2100 4:57 PM"
click_button 'Book It'
end
end.to change(#car1.appointments, :count).by(1)
end
end
end
Edit 3:
After updating to selenium-webdriver 2.53.4 and re-running the test that requires the user-login, Firefox is hanging indefinitely, and when I quit Firefox manually I get this error message with the failing test:
Failure/Error: visit new_user_session_path
Errno::ECONNREFUSED:
Connection refused - connect(2) for "127.0.0.1" port 7055
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/http/default.rb:107:in `response_for'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/http/default.rb:58:in `request'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/http/common.rb:59:in `call'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/bridge.rb:649:in `raw_execute'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/bridge.rb:627:in `execute'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/bridge.rb:134:in `get'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/common/navigation.rb:33:in `to'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/gems/capybara-2.6.2/lib/capybara/selenium/driver.rb:45:in `visit'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/gems/capybara-2.6.2/lib/capybara/session.rb:232:in `visit'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/gems/capybara-2.6.2/lib/capybara/dsl.rb:51:in `block (2 levels) in <module:DSL>'
# ./spec/spec_helper.rb:23:in `test_sign_in'
# ./spec/requests/user_pages_spec.rb:31:in `block (3 levels) in <top (required)>'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/bundler/gems/spork-224df492657e/lib/spork/test_framework/rspec.rb:12:in `run_tests'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/bundler/gems/spork-224df492657e/lib/spork/run_strategy/forking.rb:13:in `block in run'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/bundler/gems/spork-224df492657e/lib/spork/forker.rb:21:in `block in initialize'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/bundler/gems/spork-224df492657e/lib/spork/forker.rb:18:in `fork'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/bundler/gems/spork-224df492657e/lib/spork/forker.rb:18:in `initialize'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/bundler/gems/spork-224df492657e/lib/spork/run_strategy/forking.rb:9:in `new'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/bundler/gems/spork-224df492657e/lib/spork/run_strategy/forking.rb:9:in `run'
# /Users/JAckerman/.rvm/gems/ruby-2.2.4/bundler/gems/spork-224df492657e/lib/spork/server.rb:49:in `run'
Edit 4:
test.log after running the test that hangs
[1m[36mActiveRecord::SchemaMigration Load (0.6ms)[0m [1mSELECT "schema_migrations".* FROM "schema_migrations"[0m
[1m[35m (0.2ms)[0m BEGIN
[1m[36m (0.2ms)[0m [1mCOMMIT[0m
[1m[35m (0.1ms)[0m BEGIN
[1m[36m (1.7ms)[0m [1mALTER TABLE "active_admin_comments" DISABLE TRIGGER ALL;ALTER TABLE "authorizations" DISABLE TRIGGER ALL;ALTER TABLE "authorized_drivers" DISABLE TRIGGER ALL;ALTER TABLE "garagepartners" DISABLE TRIGGER ALL;ALTER TABLE "cars" DISABLE TRIGGER ALL;ALTER TABLE "locations" DISABLE TRIGGER ALL;ALTER TABLE "partners" DISABLE TRIGGER ALL;ALTER TABLE "appointments" DISABLE TRIGGER ALL;ALTER TABLE "images" DISABLE TRIGGER ALL;ALTER TABLE "garages" DISABLE TRIGGER ALL;ALTER TABLE "users" DISABLE TRIGGER ALL;ALTER TABLE "schema_migrations" DISABLE TRIGGER ALL;ALTER TABLE "companies" DISABLE TRIGGER ALL;ALTER TABLE "damages" DISABLE TRIGGER ALL;ALTER TABLE "admin_users" DISABLE TRIGGER ALL;ALTER TABLE "delayed_jobs" DISABLE TRIGGER ALL[0m
[1m[35m (2.3ms)[0m SELECT schemaname || '.' || tablename
FROM pg_tables
WHERE
tablename !~ '_prt_' AND
tablename <> 'schema_migrations' AND
schemaname = ANY (current_schemas(false))
[1m[36m (2.0ms)[0m [1mselect table_name from information_schema.views where table_schema = 'parkme3_test'[0m
[1m[35m (55.4ms)[0m TRUNCATE TABLE "public"."active_admin_comments", "public"."authorizations", "public"."authorized_drivers", "public"."garagepartners", "public"."cars", "public"."locations", "public"."partners", "public"."appointments", "public"."images", "public"."garages", "public"."users", "public"."companies", "public"."damages", "public"."admin_users", "public"."delayed_jobs" RESTART IDENTITY CASCADE;
[1m[36m (0.9ms)[0m [1mALTER TABLE "active_admin_comments" ENABLE TRIGGER ALL;ALTER TABLE "authorizations" ENABLE TRIGGER ALL;ALTER TABLE "authorized_drivers" ENABLE TRIGGER ALL;ALTER TABLE "garagepartners" ENABLE TRIGGER ALL;ALTER TABLE "schema_migrations" ENABLE TRIGGER ALL;ALTER TABLE "cars" ENABLE TRIGGER ALL;ALTER TABLE "locations" ENABLE TRIGGER ALL;ALTER TABLE "partners" ENABLE TRIGGER ALL;ALTER TABLE "appointments" ENABLE TRIGGER ALL;ALTER TABLE "images" ENABLE TRIGGER ALL;ALTER TABLE "garages" ENABLE TRIGGER ALL;ALTER TABLE "users" ENABLE TRIGGER ALL;ALTER TABLE "companies" ENABLE TRIGGER ALL;ALTER TABLE "damages" ENABLE TRIGGER ALL;ALTER TABLE "admin_users" ENABLE TRIGGER ALL;ALTER TABLE "delayed_jobs" ENABLE TRIGGER ALL[0m
[1m[35mUser Load (1.4ms)[0m SELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["email", "test_user#example.com"]]
[1m[36mUser Load (0.6ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."invitation_token" = $1 ORDER BY "users"."id" ASC LIMIT 1[0m [["invitation_token", "12f7e3e1ca7f4be3bf7ebc51410444e1b49d703cade994df75ca75a2e49fed3e"]]
[1m[35m (0.2ms)[0m SAVEPOINT active_record_1
[1m[36mSQL (0.7ms)[0m [1mINSERT INTO "users" ("receive_email_notification", "receive_text_notification", "email", "encrypted_password", "invitation_token", "invitation_created_at", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id"[0m [["receive_email_notification", "t"], ["receive_text_notification", "t"], ["email", "test_user#example.com"], ["encrypted_password", "$2a$04$dzJj7097jsrmaWOfVGqrq.F4wcKx4yktACtDVjI7IXbt6u83C7.QO"], ["invitation_token", "12f7e3e1ca7f4be3bf7ebc51410444e1b49d703cade994df75ca75a2e49fed3e"], ["invitation_created_at", "2016-07-15 15:02:23.921974"], ["created_at", "2016-07-15 15:02:23.923749"], ["updated_at", "2016-07-15 15:02:23.923749"]]
[1m[35m (0.2ms)[0m RELEASE SAVEPOINT active_record_1
[1m[36m (0.3ms)[0m [1mSAVEPOINT active_record_1[0m
[1m[35mSQL (0.5ms)[0m UPDATE "users" SET "invitation_accepted_at" = $1, "invitation_token" = $2, "updated_at" = $3 WHERE "users"."id" = $4 [["invitation_accepted_at", "2016-07-15 15:02:23.929347"], ["invitation_token", nil], ["updated_at", "2016-07-15 15:02:23.930593"], ["id", 1]]
[1m[36m (0.2ms)[0m [1mRELEASE SAVEPOINT active_record_1[0m
[1m[35m (0.1ms)[0m SAVEPOINT active_record_1
[1m[36mSQL (0.5ms)[0m [1mUPDATE "users" SET "encrypted_password" = $1, "first_name" = $2, "last_name" = $3, "updated_at" = $4 WHERE "users"."id" = $5[0m [["encrypted_password", "$2a$04$c8LSFWcTJXE7np2W838iLui3lHt7yYXSjQvhQoxt91EqkW1xvBr1q"], ["first_name", "John"], ["last_name", "Smith"], ["updated_at", "2016-07-15 15:02:23.938120"], ["id", 1]]
[1m[35m (0.3ms)[0m RELEASE SAVEPOINT active_record_1
[1m[36m (0.2ms)[0m [1mSAVEPOINT active_record_1[0m
[1m[35mSQL (0.5ms)[0m INSERT INTO "companies" ("name", "min_time_in_minutes", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["name", "company_1"], ["min_time_in_minutes", 15], ["created_at", "2016-07-15 15:02:23.977122"], ["updated_at", "2016-07-15 15:02:23.977122"]]
[1m[36m (0.3ms)[0m [1mRELEASE SAVEPOINT active_record_1[0m
[1m[35m (0.2ms)[0m SAVEPOINT active_record_1
[1m[36mSQL (0.6ms)[0m [1mINSERT INTO "garages" ("name", "time_zone", "min_time_in_minutes", "urgent_minutes", "use_acknowledgement", "use_locations", "use_damage_tracking", "use_numpad_make_appointment_form", "phone_number", "company_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING "id"[0m [["name", "garage_1"], ["time_zone", "Eastern Time (US & Canada)"], ["min_time_in_minutes", 15], ["urgent_minutes", 60], ["use_acknowledgement", "t"], ["use_locations", "t"], ["use_damage_tracking", "t"], ["use_numpad_make_appointment_form", "f"], ["phone_number", "7777777777"], ["company_id", 1], ["created_at", "2016-07-15 15:02:23.982258"], ["updated_at", "2016-07-15 15:02:23.982258"]]
[1m[35m (0.2ms)[0m RELEASE SAVEPOINT active_record_1
[1m[36m (0.2ms)[0m [1mSAVEPOINT active_record_1[0m
[1m[35mSQL (0.7ms)[0m INSERT INTO "cars" ("make", "car_model", "year", "car_number", "garage_id", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id" [["make", "make_1"], ["car_model", "car_model_1"], ["year", 2014], ["car_number", 1], ["garage_id", 1], ["user_id", 1], ["created_at", "2016-07-15 15:02:23.988597"], ["updated_at", "2016-07-15 15:02:23.988597"]]
[1m[36m (0.2ms)[0m [1mRELEASE SAVEPOINT active_record_1[0m
[1m[35m (0.2ms)[0m SAVEPOINT active_record_1
[1m[36mSQL (0.3ms)[0m [1mINSERT INTO "companies" ("name", "min_time_in_minutes", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"[0m [["name", "company_2"], ["min_time_in_minutes", 15], ["created_at", "2016-07-15 15:02:23.996186"], ["updated_at", "2016-07-15 15:02:23.996186"]]
[1m[35m (0.2ms)[0m RELEASE SAVEPOINT active_record_1
[1m[36m (0.2ms)[0m [1mSAVEPOINT active_record_1[0m
[1m[35mSQL (0.4ms)[0m INSERT INTO "garages" ("name", "time_zone", "min_time_in_minutes", "urgent_minutes", "use_acknowledgement", "use_locations", "use_damage_tracking", "use_numpad_make_appointment_form", "phone_number", "company_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING "id" [["name", "garage_2"], ["time_zone", "Eastern Time (US & Canada)"], ["min_time_in_minutes", 15], ["urgent_minutes", 60], ["use_acknowledgement", "t"], ["use_locations", "t"], ["use_damage_tracking", "t"], ["use_numpad_make_appointment_form", "f"], ["phone_number", "7777777777"], ["company_id", 2], ["created_at", "2016-07-15 15:02:23.999804"], ["updated_at", "2016-07-15 15:02:23.999804"]]
[1m[36m (0.2ms)[0m [1mRELEASE SAVEPOINT active_record_1[0m
[1m[35m (0.1ms)[0m SAVEPOINT active_record_1
[1m[36mSQL (0.4ms)[0m [1mINSERT INTO "cars" ("make", "car_model", "year", "car_number", "garage_id", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id"[0m [["make", "make_2"], ["car_model", "car_model_2"], ["year", 2014], ["car_number", 2], ["garage_id", 2], ["user_id", 1], ["created_at", "2016-07-15 15:02:24.003820"], ["updated_at", "2016-07-15 15:02:24.003820"]]
[1m[35m (0.2ms)[0m RELEASE SAVEPOINT active_record_1
[1m[36m (0.2ms)[0m [1mSAVEPOINT active_record_1[0m
[1m[35mSQL (0.6ms)[0m INSERT INTO "appointments" ("aasm_state", "pickuptime", "car_id", "garage_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["aasm_state", "scheduled"], ["pickuptime", "2016-07-16 15:02:24.006227"], ["car_id", 1], ["garage_id", 1], ["created_at", "2016-07-15 15:02:24.026603"], ["updated_at", "2016-07-15 15:02:24.026603"]]
[1m[36m (0.2ms)[0m [1mRELEASE SAVEPOINT active_record_1[0m
[1m[35m (0.2ms)[0m SAVEPOINT active_record_1
[1m[36mSQL (0.4ms)[0m [1mINSERT INTO "appointments" ("aasm_state", "pickuptime", "car_id", "garage_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"[0m [["aasm_state", "scheduled"], ["pickuptime", "2016-07-17 15:02:24.006227"], ["car_id", 1], ["garage_id", 1], ["created_at", "2016-07-15 15:02:24.033088"], ["updated_at", "2016-07-15 15:02:24.033088"]]
[1m[35m (0.3ms)[0m RELEASE SAVEPOINT active_record_1
[1m[36m (0.2ms)[0m [1mSAVEPOINT active_record_1[0m
[1m[35mSQL (0.4ms)[0m INSERT INTO "appointments" ("aasm_state", "pickuptime", "car_id", "garage_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["aasm_state", "scheduled"], ["pickuptime", "2016-07-15 15:01:54.006233"], ["car_id", 1], ["garage_id", 1], ["created_at", "2016-07-15 15:02:24.039517"], ["updated_at", "2016-07-15 15:02:24.039517"]]
[1m[36m (0.3ms)[0m [1mRELEASE SAVEPOINT active_record_1[0m
[1m[35m (0.2ms)[0m SAVEPOINT active_record_1
[1m[36mUser Exists (0.5ms)[0m [1mSELECT 1 AS one FROM "users" WHERE "users"."email" = 'person_1#example.com' LIMIT 1[0m
[1m[35mSQL (0.4ms)[0m INSERT INTO "users" ("receive_email_notification", "receive_text_notification", "email", "encrypted_password", "invitation_accepted_at", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["receive_email_notification", "t"], ["receive_text_notification", "t"], ["email", "person_1#example.com"], ["encrypted_password", "$2a$04$glYjOuWxkRp06jc/l1X0ceeI5OD.eqWMzsnt/MRhizfX7RuD7ti9m"], ["invitation_accepted_at", "2016-07-15 14:02:24.045381"], ["created_at", "2016-07-15 15:02:24.053170"], ["updated_at", "2016-07-15 15:02:24.053170"]]
[1m[36m (0.2ms)[0m [1mRELEASE SAVEPOINT active_record_1[0m
[1m[35m (0.2ms)[0m SAVEPOINT active_record_1
[1m[36mSQL (0.3ms)[0m [1mINSERT INTO "companies" ("name", "min_time_in_minutes", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"[0m [["name", "company_3"], ["min_time_in_minutes", 15], ["created_at", "2016-07-15 15:02:24.060156"], ["updated_at", "2016-07-15 15:02:24.060156"]]
[1m[35m (0.3ms)[0m RELEASE SAVEPOINT active_record_1
[1m[36m (0.1ms)[0m [1mSAVEPOINT active_record_1[0m
[1m[35mSQL (0.4ms)[0m INSERT INTO "garages" ("name", "time_zone", "min_time_in_minutes", "urgent_minutes", "use_acknowledgement", "use_locations", "use_damage_tracking", "use_numpad_make_appointment_form", "phone_number", "company_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING "id" [["name", "garage_3"], ["time_zone", "Eastern Time (US & Canada)"], ["min_time_in_minutes", 15], ["urgent_minutes", 60], ["use_acknowledgement", "t"], ["use_locations", "t"], ["use_damage_tracking", "t"], ["use_numpad_make_appointment_form", "f"], ["phone_number", "7777777777"], ["company_id", 3], ["created_at", "2016-07-15 15:02:24.063107"], ["updated_at", "2016-07-15 15:02:24.063107"]]
[1m[36m (0.3ms)[0m [1mRELEASE SAVEPOINT active_record_1[0m
[1m[35m (0.1ms)[0m SAVEPOINT active_record_1
[1m[36mSQL (0.3ms)[0m [1mINSERT INTO "cars" ("make", "car_model", "year", "car_number", "garage_id", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id"[0m [["make", "diff_make"], ["car_model", "car_model_3"], ["year", 2014], ["car_number", 3], ["garage_id", 3], ["user_id", 2], ["created_at", "2016-07-15 15:02:24.066940"], ["updated_at", "2016-07-15 15:02:24.066940"]]
[1m[35m (0.2ms)[0m RELEASE SAVEPOINT active_record_1
[1m[36m (0.2ms)[0m [1mSAVEPOINT active_record_1[0m
[1m[35mSQL (0.4ms)[0m INSERT INTO "appointments" ("aasm_state", "pickuptime", "car_id", "garage_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["aasm_state", "scheduled"], ["pickuptime", "2016-07-16 16:02:24.006227"], ["car_id", 3], ["garage_id", 3], ["created_at", "2016-07-15 15:02:24.071953"], ["updated_at", "2016-07-15 15:02:24.071953"]]
[1m[36m (0.2ms)[0m [1mRELEASE SAVEPOINT active_record_1[0m
Started GET "/login" for 127.0.0.1 at 2016-07-15 11:02:26 -0400
Processing by Users::SessionsController#new as HTML
Rendered users/sessions/_new.html.erb (75.4ms)
Rendered users/sessions/new.html.erb within layouts/application (82.6ms)
Rendered layouts/_shim.html.erb (0.2ms)
Rendered application/_favicon.html.erb (1.2ms)
Rendered users/sessions/_new.html.erb (8.2ms)
Rendered partners/sessions/_new.html.erb (16.3ms)
Rendered layouts/_header.html.erb (27.6ms)
Rendered layouts/_footer.html.erb (1.2ms)
Rendered layouts/_google_analytics.html.erb (1.0ms)
Completed 200 OK in 206ms (Views: 190.7ms | ActiveRecord: 0.0ms)
Started POST "/login" for 127.0.0.1 at 2016-07-15 11:02:28 -0400
Processing by Users::SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "user"=>{"email"=>"test_user#example.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Sign in"}
This is where it hung. The rest of the log appeared after the test timed out.
[1m[35m (0.5ms)[0m ALTER TABLE "active_admin_comments" DISABLE TRIGGER ALL;ALTER TABLE "authorizations" DISABLE TRIGGER ALL;ALTER TABLE "authorized_drivers" DISABLE TRIGGER ALL;ALTER TABLE "garagepartners" DISABLE TRIGGER ALL;ALTER TABLE "schema_migrations" DISABLE TRIGGER ALL;ALTER TABLE "cars" DISABLE TRIGGER ALL;ALTER TABLE "locations" DISABLE TRIGGER ALL;ALTER TABLE "partners" DISABLE TRIGGER ALL;ALTER TABLE "appointments" DISABLE TRIGGER ALL;ALTER TABLE "images" DISABLE TRIGGER ALL;ALTER TABLE "garages" DISABLE TRIGGER ALL;ALTER TABLE "users" DISABLE TRIGGER ALL;ALTER TABLE "companies" DISABLE TRIGGER ALL;ALTER TABLE "damages" DISABLE TRIGGER ALL;ALTER TABLE "admin_users" DISABLE TRIGGER ALL;ALTER TABLE "delayed_jobs" DISABLE TRIGGER ALL
[1m[36m (45.9ms)[0m [1mTRUNCATE TABLE "public"."active_admin_comments", "public"."authorizations", "public"."authorized_drivers", "public"."garagepartners", "public"."cars", "public"."locations", "public"."partners", "public"."appointments", "public"."images", "public"."garages", "public"."users", "public"."companies", "public"."damages", "public"."admin_users", "public"."delayed_jobs" RESTART IDENTITY CASCADE;[0m
[1m[35m (0.8ms)[0m ALTER TABLE "active_admin_comments" ENABLE TRIGGER ALL;ALTER TABLE "authorizations" ENABLE TRIGGER ALL;ALTER TABLE "authorized_drivers" ENABLE TRIGGER ALL;ALTER TABLE "garagepartners" ENABLE TRIGGER ALL;ALTER TABLE "schema_migrations" ENABLE TRIGGER ALL;ALTER TABLE "cars" ENABLE TRIGGER ALL;ALTER TABLE "locations" ENABLE TRIGGER ALL;ALTER TABLE "partners" ENABLE TRIGGER ALL;ALTER TABLE "appointments" ENABLE TRIGGER ALL;ALTER TABLE "images" ENABLE TRIGGER ALL;ALTER TABLE "garages" ENABLE TRIGGER ALL;ALTER TABLE "users" ENABLE TRIGGER ALL;ALTER TABLE "companies" ENABLE TRIGGER ALL;ALTER TABLE "damages" ENABLE TRIGGER ALL;ALTER TABLE "admin_users" ENABLE TRIGGER ALL;ALTER TABLE "delayed_jobs" ENABLE TRIGGER ALL
This was in the Spork console after the test timed out:
1.1) Failure/Error: click_button 'Sign in'
Net::ReadTimeout:
Net::ReadTimeout
users/sessions_controller.rb (using Devise)
class Users::SessionsController < Devise::SessionsController
include ApplicationHelper
def create
super
end
def new
render 'new'
end
def after_sign_in_path_for(resource)
user_path(resource)
end
end
Got stuck at this point when stepping through the controller using byebug:
in /Users/JAckerman/.rvm/gems/ruby-2.2.4/gems/devise-3.5.6/app/controllers/devise/sessions_controller.rb
12: respond_with(resource, serialize_options(resource))
13: end
14:
15: # POST /resource/sign_in
16: def create
=> 17: self.resource = warden.authenticate!(auth_options)
After stepping into that, I got stuck here:
in /Users/JAckerman/.rvm/gems/ruby-2.2.4/gems/warden-1.2.6/lib/warden/proxy.rb
122: # Example
123: # env['warden'].authenticate!(:password, :scope => :publisher) # throws if it cannot authenticate
124: #
125: # :api: public
126: def authenticate!(*args)
=> 127: user, opts = _perform_authentication(*args)
128: throw(:warden, opts) unless user
129: user
130: end
After pulling out a lot of hair, this is what ended up working:
Change:
# configure database cleaner
config.before(:suite) do
DatabaseCleaner.start
DatabaseCleaner.clean_with(:truncation)
end
To:
# configure database cleaner
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
And add config.use_transactional_fixtures = false to rails_helper.rb, which had been there at the beginning and had been removed at some point in the many iterations of configurations that I had tried.
Either way, hopefully this saves someone else a headache!

Specs are long to run because of truncation of tables

I have a Rails 4 app with simple specs. When I run a spec, it takes 26 seconds. If I look at the log, I can see this :
(38.5ms) ALTER TABLE "schema_migrations" DISABLE TRIGGER ALL;ALTER TABLE .............# tons of tables
(10.3ms) SELECT schemaname || '.' || tablename
FROM pg_tables
WHERE
tablename !~ '_prt_' AND
tablename <> 'schema_migrations' AND
schemaname = ANY (current_schemas(false))
(2.3ms) select table_name from information_schema.views where table_schema = 'lap-test'
(10708.2ms) TRUNCATE TABLE "public"."bounded_facets_service_boutiques", "public"."versions", ..... # Tons of tables
(10823.0ms) TRUNCATE TABLE "public"."bounded_facets_service_boutiques", "public"."versions", .... #Tons of tables
(26.2ms) ALTER TABLE "schema_migrations" ENABLE TRIGGER ALL;ALTER TABLE "bounded_facets_service_boutiques" ENABLE TRIGGER ALL;ALTER TABLE "versions" .... #Tons of tables
(0.6ms) BEGIN
(0.3ms) COMMIT
(0.2ms) BEGIN
(0.2ms) SAVEPOINT active_record_1
(0.2ms) RELEASE SAVEPOINT active_record_1
(0.2ms) SAVEPOINT active_record_1
(0.5ms) SAVEPOINT active_record_2
Administrator Exists (1.9ms) SELECT 1 AS one FROM "administrators" WHERE "administrators"."email" = 'person1#labandprocess.com' LIMIT 1
SQL (2.3ms) INSERT INTO "administrators" .....
(0.6ms) RELEASE SAVEPOINT active_record_2
(0.4ms) ROLLBACK TO SAVEPOINT active_record_1
(0.6ms) ROLLBACK
As you can see, The truncation takes 10 seconds 2 times.
I use database cleaner with this :
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
end
I tested with other strategies without result.
There is a lot of seeds in development mod but it's on another database. There is 107 models in this project.
Is there a solution ?

Rspec and Capybara throw inconsistent Postgresql errors each time I run my tests

Postgresql throws various errors or stalls I run my feature test suite which uses Rspec, Capybara-Selenium, and DatabaseCleaner. I can't pin it down because the error changes every time. Sometimes there are no errors at all. I would appreciate any guidance out there.
Here's Error1:
Processing by Api::V1::Company::WagesController#create as JSON
Parameters: {"wage"=>{"user_id"=>33, "amount"=>"100000"}, "user_id"=>"33"}
(39.3ms) SELECT COUNT(*) FROM "users"
(1.8ms) BEGIN
NoMethodError: undefined method `nfields' for nil:NilClass: SELECT tablename
FROM pg_tables
WHERE schemaname = ANY (current_schemas(false))
SQL (12.6ms) INSERT INTO "wages" ("amount", "created_at", "updated_at", "user_id") VALUES ($1, $2, $3, $4) RETURNING "id" [["amount", "100000.0"], ["created_at", "2014-06-17 19:47:21.901609"], ["updated_at", "2014-06-17 19:47:21.901609"], ["user_id", 33]]
(5.1ms) COMMIT
Error2:
Started POST "/api/v1/company/users/2/wages" for 127.0.0.1 at 2014-06-17 15:51:32 -0400
Processing by Api::V1::Company::WagesController#create as JSON
Parameters: {"wage"=>{"user_id"=>2, "amount"=>"100000"}, "user_id"=>"2"}
PG::UndefinedTable: ERROR: relation "id" does not exist
: SELECT a.attname, format_type(a.atttypid, a.atttypmod),
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = '"wages"'::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
Error3:
An error occurred in an after hook
ActiveRecord::StatementInvalid: PG::NoActiveSqlTransaction: ERROR: ROLLBACK TO SAVEPOINT can only be used in transaction blocks
: ROLLBACK TO SAVEPOINT active_record_0
occurred at /Users/codylittlewood/.rvm/gems/ruby-2.1.1#bitcoinpayroll/gems/activerecord-4.1.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:128:in `async_exec'
Error4: (where it just hangs)
(3.2ms) ALTER TABLE "companies" DISABLE TRIGGER ALL;ALTER TABLE "schema_migrations" DISABLE TRIGGER ALL;ALTER TABLE "payrolls" DISABLE TRIGGER ALL;ALTER TABLE "payslips" DISABLE TRIGGER ALL;ALTER TABLE "users" DISABLE TRIGGER ALL;ALTER TABLE "wages" DISABLE TRIGGER ALL
(18.5ms) TRUNCATE TABLE "companies", "payrolls", "payslips", "users", "wages" RESTART IDENTITY CASCADE;
Started POST "/api/v1/company/users/4/wages" for 127.0.0.1 at 2014-06-17 15:57:41 -0400
Processing by Api::V1::Company::WagesController#create as JSON
Parameters: {"wage"=>{"user_id"=>4, "amount"=>"100000"}, "user_id"=>"4"}
No code was changed between any of these tests and different errors each time.
Here's my spec_helper.rb:
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
config.include FactoryGirl::Syntax::Methods
# 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 = false
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
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"
end
Here's my feature tests spec/features/user_spec.rb:
require 'spec_helper'
include Warden::Test::Helpers
Warden.test_mode!
feature 'Employee management' do
scenario "adds a new user", :js => true do
admin = create(:admin)
admin.confirmed_at = Time.now
admin.save
login_as(admin, :scope => :user)
visit root_path
expect{
#click_link 'Dashboard'
click_link 'Company employees'
click_link 'Add an employee'
fill_in 'employee[first_name]', with: 'Test'
fill_in 'employee[last_name]', with: 'User'
fill_in 'employee[email]', with: 'newuser#example.com'
select "January", from: 'employee[hire_month]'
select "1", from: 'employee[hire_day]'
select "2014", from: 'employee[hire_year]'
fill_in 'employee[wage]', with: '100000'
click_button 'Add employee'
}.to change(User, :count).by(1)
logout :admin
end
end
Warden.test_reset!
Looks as though there are multiple threads trying to access the same database connection at once, and it's mixing queries. There's no reason for those queries to happen simultaneously.
Maybe check out your code to see if there's something creating a shared connection? See if literally commenting out the shared connection code works?

Resources