Reputation: 136
I need to test file uploads page with Capybara and Selenium.
I wrote this test:
require 'rails_helper'
describe 'Images', type: :feature do
before(:each) do
@user = create(:user)
visit '/users/sign_in'
fill_in 'sing-in-email-input', with: @user.email
fill_in 'sign-in-password-input', with: @user.password
click_button 'btn-sign-in'
visit '/categories'
click_on 'btn-new-category'
expect(current_path) == new_category_path
fill_in 'category_name', with: 'Test'
click_button 'btn-create category'
visit '/categories'
first('.fa', :visible => false).click
expect(current_path) == category_path(id: Category.last.slug.to_s)
end
it 'should allow a registered user to create image and go to it page', js: true do
click_on 'btn-upload-images'
expect(current_path) == new_image_path(id: Category.last.slug.to_s)
attach_file('image[image]',
File.join(Rails.root, '/spec/fixtures/solnce-kosmos-merkuriy.jpg'), :visible => false)
click_on('btn-upload-img')
end
end
I am not able to continue write this test and check was this image successfully uploaded because on this line:
click_on('btn-upload-img')
I got this error:
Failure/Error: raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}"
ActionController::RoutingError:
No route matches [GET] "/home/Anton-S/RubymineProjects/rails_projects/gallery/spec/support/uploads/image/image/8790/solnce-kosmos-merkuriy.jpg"
# /var/lib/gems/2.3.0/gems/railties-5.1.4/lib/rails/rack/logger.rb:36:in `call_app'
# /var/lib/gems/2.3.0/gems/railties-5.1.4/lib/rails/rack/logger.rb:24:in `block in call'
# /var/lib/gems/2.3.0/gems/railties-5.1.4/lib/rails/rack/logger.rb:24:in `call'
# /var/lib/gems/2.3.0/gems/rack-2.0.3/lib/rack/method_override.rb:22:in `call'
# /var/lib/gems/2.3.0/gems/rack-2.0.3/lib/rack/runtime.rb:22:in `call'
# /var/lib/gems/2.3.0/gems/rack-2.0.3/lib/rack/sendfile.rb:111:in `call'
# /var/lib/gems/2.3.0/gems/railties-5.1.4/lib/rails/engine.rb:522:in `call'
# /var/lib/gems/2.3.0/gems/rack-2.0.3/lib/rack/urlmap.rb:68:in `block in call'
# /var/lib/gems/2.3.0/gems/rack-2.0.3/lib/rack/urlmap.rb:53:in `each'
# /var/lib/gems/2.3.0/gems/rack-2.0.3/lib/rack/urlmap.rb:53:in `call'
# /var/lib/gems/2.3.0/gems/capybara-2.16.1/lib/capybara/server.rb:44:in `call'
# /var/lib/gems/2.3.0/gems/rack-2.0.3/lib/rack/handler/webrick.rb:86:in `service'
# ------------------
# --- Caused by: ---
# Capybara::CapybaraError:
# Your application server raised an error - It has been raised in your test code because Capybara.raise_server_errors == true
# /var/lib/gems/2.3.0/gems/capybara-2.16.1/lib/capybara/session.rb:145:in `raise_server_error!'
Finished in 17.15 seconds (files took 2.55 seconds to load)
133 examples, 1 failure
Failed examples:
rspec ./spec/features/images_spec.rb:20 # Images should allow a registered user to create image and go to it page
I have checked that I realy have this file
/spec/fixtures/solnce-kosmos-merkuriy.jpg
on the right place.
Here is my /config/initializers/carrierwave.rb
if Rails.env.test? || Rails.env.cucumber?
CarrierWave.configure do |config|
config.storage = :file
config.enable_processing = false
end
# make sure our uploader is auto-loaded
ImageUploader
# use different dirs when testing
CarrierWave::Uploader::Base.descendants.each do |klass|
next if klass.anonymous?
klass.class_eval do
def cache_dir
"#{Rails.root}/spec/support/uploads/tmp"
end
def store_dir
"#{Rails.root}/spec/support/uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
end
end
my rails_helper.rb
require 'support/factory_bot'
require 'spec_helper'
require 'shoulda/matchers'
require 'capybara/rspec'
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 'rspec/rails'
ActiveRecord::Migration.maintain_test_schema!
module DeviseRequestSpecHelpers
include Warden::Test::Helpers
def sign_in(resource_or_scope, resource = nil)
resource ||= resource_or_scope
scope = Devise::Mapping.find_scope!(resource_or_scope)
login_as(resource, scope: scope)
end
def sign_out(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
logout(scope)
end
end
RSpec.configure do |config|
Capybara.ignore_hidden_elements = false
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
config.include Devise::Test::ControllerHelpers, type: :controller
config.include DeviseRequestSpecHelpers, type: :request
end
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
My spec_helper.rb
RSpec.configure do |config|
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
config.shared_context_metadata_behavior = :apply_to_host_groups
end
My view template for this images upload page:
.row.main-new-image
= form_for @image, url: create_image_path, html: {multipart: true, method: :post, remote: true } do |form|
#new_image_error_explanation
.field
.p.text-center
%span.btn.btn-new-image{id: 'new-image-button'}
%p#p-new-image-button Choose image
\#{form.file_field :image, id: 'new-image-id'}
.field
= form.hidden_field :user_id, value: current_user.id
.actions
.p.text-center
= form.submit 'Upload', class: 'btn button-upload-img', id: 'btn-upload-img'
All my other Capybara and RSpec tests works fine.
Please help me to understand what is the reason of this issue and how to solve it and prevent in the future.
I can provide more information if it can help to solve this issue.
UPDATE 1
After I read comment of Thomas Walpole I decide to update my code and try some other features. I include new gem
gem 'database_cleaner'
Also I have added new code to clear test uploaded code. Here is updated rails_helper.rb
require 'support/factory_bot'
require 'spec_helper'
require 'shoulda/matchers'
require 'capybara/rspec'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
ActiveRecord::Migration.maintain_test_schema!
module DeviseRequestSpecHelpers
include Warden::Test::Helpers
def sign_in(resource_or_scope, resource = nil)
resource ||= resource_or_scope
scope = Devise::Mapping.find_scope!(resource_or_scope)
login_as(resource, scope: scope)
end
def sign_out(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
logout(scope)
end
end
RSpec.configure do |config|
Capybara.javascript_driver = :selenium
Capybara.ignore_hidden_elements = true
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app, browser: :firefox)
end
config.include Capybara::DSL
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
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.after(:all) do
if Rails.env.test?
FileUtils.rm_rf(Dir["#{Rails.root}/spec/support/uploads"])
end
end
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
config.include Devise::Test::ControllerHelpers, type: :controller
config.include DeviseRequestSpecHelpers, type: :request
end
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
Here is my updated test
require 'rails_helper'
describe 'Images', type: :feature do
before(:each) do
@user = create(:user)
visit '/users/sign_in'
fill_in 'sing-in-email-input', with: @user.email
fill_in 'sign-in-password-input', with: @user.password
click_button 'btn-sign-in'
visit '/categories'
click_on 'btn-new-category'
have_current_path(new_category_path)
fill_in 'category_name', with: 'Test'
click_button 'btn-create category'
visit '/categories'
first('.fa', :visible => false).click
have_current_path(category_path(id: Category.last.slug.to_s))
end
#ISSUE WITH
it 'should allow a registered user to create image and go to it page', :driver => :selenium do
click_on 'btn-upload-images'
have_current_path(new_image_path(id: Category.last.slug.to_s))
attach_file('image[image]',
File.join(Rails.root, '/spec/fixtures/solnce-kosmos-merkuriy.jpg'), :visible => false)
click_on('btn-upload-img')
end
end
As Thomas Walpole told me, I checked test logs and saw next (about current test):
Started GET "/en/categories/test/new_image" for 127.0.0.1 at 2018-01-30 14:33:26 +0200
Processing by ImagesController#new as HTML
Parameters: {"locale"=>"en", "id"=>"test"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 22], ["LIMIT", 1]]
(0.2ms) SAVEPOINT active_record_2
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 22], ["LIMIT", 1]]
SQL (0.3ms) INSERT INTO "user_actions" ("user_id", "action_type", "url", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["user_id", 22], ["action_type", "navigation"], ["url", "http://127.0.0.1:38226/en/categories/test/new_image"], ["created_at", "2018-01-30 12:33:26.645909"], ["updated_at", "2018-01-30 12:33:26.645909"]]
(0.1ms) RELEASE SAVEPOINT active_record_2
Rendering images/new.html.haml within layouts/application
Rendered images/_form.html.haml (5.2ms)
Rendered images/new.html.haml within layouts/application (7.5ms)
Category Load (1.1ms) SELECT DISTINCT categories.*, COUNT(images.*) AS images_count, categories.*, COUNT(likes.*) AS likes_count, categories.*, COUNT(comments.*) AS comments_count FROM "categories" LEFT OUTER JOIN "images" ON "images"."category_id" = "categories"."id" LEFT OUTER JOIN "images" "images_categories_join" ON "images_categories_join"."category_id" = "categories"."id" LEFT OUTER JOIN "likes" ON "likes"."image_id" = "images_categories_join"."id" LEFT OUTER JOIN "images" "images_categories_join_2" ON "images_categories_join_2"."category_id" = "categories"."id" LEFT OUTER JOIN "comments" ON "comments"."image_id" = "images_categories_join_2"."id" GROUP BY categories.id ORDER BY images_count DESC, likes_count DESC, comments_count DESC LIMIT $1 [["LIMIT", 5]]
Rendered layouts/_header.html.haml (4.3ms)
Rendered layouts/_footer.haml (0.0ms)
Completed 200 OK in 21ms (Views: 12.6ms | ActiveRecord: 2.1ms)
Category Load (0.6ms) SELECT "categories".* FROM "categories" ORDER BY "categories"."id" DESC LIMIT $1 [["LIMIT", 1]]
Started POST "/en/categories/test/create_image" for 127.0.0.1 at 2018-01-30 14:33:26 +0200
Processing by ImagesController#create as JS
Parameters: {"utf8"=>"✓", "image"=>{"image"=>#<ActionDispatch::Http::UploadedFile:0x0000000ae4e008 @tempfile=#<Tempfile:/tmp/RackMultipart20180130-28977-1nptliu.jpg>, @original_filename="solnce-kosmos-merkuriy.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"image[image]\"; filename=\"solnce-kosmos-merkuriy.jpg\"\r\nContent-Type: image/jpeg\r\n">, "user_id"=>"22"}, "commit"=>"Upload", "locale"=>"en", "id"=>"test"}
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."slug" = $1 LIMIT $2 [["slug", "test"], ["LIMIT", 1]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 22], ["LIMIT", 1]]
(0.3ms) SAVEPOINT active_record_2
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 22], ["LIMIT", 1]]
Category Load (0.2ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT $2 [["id", 18], ["LIMIT", 1]]
SQL (0.4ms) INSERT INTO "images" ("image", "category_id", "created_at", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["image", "solnce-kosmos-merkuriy.jpg"], ["category_id", 18], ["created_at", "2018-01-30 12:33:26.945577"], ["updated_at", "2018-01-30 12:33:26.945577"], ["user_id", 22]]
(0.2ms) RELEASE SAVEPOINT active_record_2
Redirected to http://127.0.0.1:38226/en/categories/test/12
Completed 200 OK in 22ms (ActiveRecord: 1.6ms)
Started GET "/en/categories/test/12" for 127.0.0.1 at 2018-01-30 14:33:26 +0200
Processing by ImagesController#show as HTML
Parameters: {"locale"=>"en", "id"=>"test", "image_id"=>"12"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 22], ["LIMIT", 1]]
(0.1ms) SAVEPOINT active_record_2
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 22], ["LIMIT", 1]]
SQL (0.3ms) INSERT INTO "user_actions" ("user_id", "action_type", "url", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["user_id", 22], ["action_type", "navigation"], ["url", "http://127.0.0.1:38226/en/categories/test/12"], ["created_at", "2018-01-30 12:33:26.966397"], ["updated_at", "2018-01-30 12:33:26.966397"]]
(0.1ms) RELEASE SAVEPOINT active_record_2
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."slug" = $1 LIMIT $2 [["slug", "test"], ["LIMIT", 1]]
Image Load (0.2ms) SELECT "images".* FROM "images" WHERE "images"."category_id" = $1 AND "images"."id" = $2 LIMIT $3 [["category_id", 18], ["id", 12], ["LIMIT", 1]]
Like Load (0.2ms) SELECT "likes".* FROM "likes" WHERE "likes"."image_id" = $1 AND "likes"."user_id" = $2 LIMIT $3 [["image_id", 12], ["user_id", 22], ["LIMIT", 1]]
Rendering images/show.html.haml within layouts/application
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 22], ["LIMIT", 1]]
(0.3ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."image_id" = $1 [["image_id", 12]]
Like Load (0.2ms) SELECT "likes".* FROM "likes" WHERE "likes"."user_id" = $1 AND "likes"."image_id" = 12 LIMIT $2 [["user_id", 22], ["LIMIT", 1]]
(0.3ms) SELECT COUNT(*) FROM "likes" WHERE "likes"."image_id" = $1 [["image_id", 12]]
Rendered likes/_like.html.haml (3.2ms)
Rendered likes/_like_form.html.haml (7.3ms)
Rendered comments/_comments.html.haml (2.7ms)
Rendered comments/_comments_container.html.haml (5.1ms)
Rendered images/show.html.haml within layouts/application (25.6ms)
Category Load (1.3ms) SELECT DISTINCT categories.*, COUNT(images.*) AS images_count, categories.*, COUNT(likes.*) AS likes_count, categories.*, COUNT(comments.*) AS comments_count FROM "categories" LEFT OUTER JOIN "images" ON "images"."category_id" = "categories"."id" LEFT OUTER JOIN "images" "images_categories_join" ON "images_categories_join"."category_id" = "categories"."id" LEFT OUTER JOIN "likes" ON "likes"."image_id" = "images_categories_join"."id" LEFT OUTER JOIN "images" "images_categories_join_2" ON "images_categories_join_2"."category_id" = "categories"."id" LEFT OUTER JOIN "comments" ON "comments"."image_id" = "images_categories_join_2"."id" GROUP BY categories.id ORDER BY images_count DESC, likes_count DESC, comments_count DESC LIMIT $1 [["LIMIT", 5]]
Rendered layouts/_header.html.haml (4.6ms)
Rendered layouts/_footer.haml (0.1ms)
Completed 200 OK in 43ms (Views: 30.0ms | ActiveRecord: 4.1ms)
Started GET "/home/Anton-S/RubymineProjects/rails_projects/gallery/spec/support/uploads/image/image/12/solnce-kosmos-merkuriy.jpg" for 127.0.0.1 at 2018-01-30 14:33:27 +0200
(0.2ms) ROLLBACK TO SAVEPOINT active_record_1
(0.1ms) ROLLBACK
(0.1ms) BEGIN
(0.1ms) COMMIT
(0.0ms) BEGIN
(0.0ms) SAVEPOINT active_record_1
(0.1ms) SAVEPOINT active_record_2
As I understand, image was successfully uploaded. But I still get this error
Failure/Error: raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}"
ActionController::RoutingError:
No route matches [GET] "/home/Anton-S/RubymineProjects/rails_projects/gallery/spec/support/uploads/image/image/12/solnce-kosmos-merkuriy.jpg"
UPDATE 2
Unfortunately the only solution I found is to set in /config/environments/test.rb
config.action_dispatch.show_exceptions = true
But I still think that there is better solution.
Upvotes: 0
Views: 1646
Reputation: 49950
So, from the logs, we can see the file is being successfully uploaded.
The issue is that when the show page is rendered the images are being added to the HTML with urls like '/home/Anton-S/RubymineProjects/rails_projects/gallery/spec/support/uploads/image/image/12/solnce-kosmos-merkuriy.jpg' which won't work because the rails app won't respond with random files from outside of the public
directory in the apps root. Doing so would be a huge security issue. The easiest solution is for you to just store the images into the public
directory so the rails app will serve them as static assets. Something along the lines of
def cache_dir
"public/test/uploads/tmp"
end
def store_dir
"public/test/uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
Note: I also commented on your use of the have_current_path
matcher.
Upvotes: 2