How to test a rake task with RSpec? - ruby-on-rails

I have an Ruby 2.1/Rails 3.2 application which uses the asset pipeline. We are also using a fragile (alpha) gem which causes "rake assets:precompile" to fail at times. I would like to write an rspec test which ensures that this rake task always passes before we commit our code.
I wrote a test in spec/asset_precompile_spec.rb which looks like this:
require 'spec_helper'
require 'rake'
describe 'assets:precompile' do
before { MyApp::Application.load_tasks }
it { expect { Rake::Task['assets:precompile'].invoke }.not_to raise_exception }
end
I then ran it on the command line using
rspec spec/lib/assets_precompile_spec.rb
The output I got looked like this:
1) assets:precompile
Failure/Error: it { expect { Rake::Task['assets:precompile'].invoke }.not_to raise_exception }
expected no Exception, got #<RuntimeError: Command failed with status (1): [/home/railsdev/.rvm/rubies/ruby-2.1.2/bin/...]> with backtrace:
# ./spec/lib/assets_precompile_spec.rb:7:in `block (3 levels) in <top (required)>'
# ./spec/lib/assets_precompile_spec.rb:7:in `block (2 levels) in <top (required)>'
# ./spec/lib/assets_precompile_spec.rb:7:in `block (2 levels) in <top (required)>'
Finished in 0.71247 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/lib/assets_precompile_spec.rb:7 # assets:precompile
I have looked far & wide, and I can't find any example to run "rake assets:precompile" which actually works in my RSpec environment. I have tried explicitly loading the spec_helper.rb file, I have tried explicitly requiring "factory_girl", but I cannot find anything which works.
Is there a way to make a test run this rake task run in a RSpec test?

Try Rake::Task['assets:precompile:all'].invoke
instead of Rake::Task['assets:precompile'].invoke
In my case it helped.

Related

Rspec giving databasecleaner problems in a custom folder

I have opened a folder spec/features. When I launch rspec spec/ everything goes well, but if I do rspec spec/features I get:
An error occurred in a before(:suite) hook.
Failure/Error: DatabaseCleaner[:active_record].strategy = :transaction
NameError:
uninitialized constant DatabaseCleaner
# ./spec/spec_helper.rb:22:in `block (2 levels) in <top (required)>'
what could be happening?

Rails::TestUnit::Runner.run NameError: uninitialized constant

On Rails 6 (6.1.4.1) we had a RakeFile that would run a subset of tests. For example:
# lib/tasks/carrier.rake
namespace :test do
task carriers: "test:prepare" do
$: << "test"
test_files = FileList["test/models/carrier_test.rb",
"test/controllers/admin/carriers/**/*_test.rb",
"test/system/admin/carriers/**/*_test.rb"]
Rails::TestUnit::Runner.run(test_files)
end
end
This would execute just fine when called:
rails test:carriers
However, somewhere along the way, something changed and we began seeing errors when trying to run our RakeFile test tasks. (I haven't tracked down exactly what changed and when it changed -- perhaps it was part of the Rails 7 release.) Here's the error we began seeing:
rails aborted!
NameError: uninitialized constant Shoulda
Shoulda::Matchers.configure do |config|
^^^^^^^
/path/test/test_helper.rb:15:in `<main>'
/path/test/models/carrier_test.rb:1:in `<main>'
/path/lib/tasks/carriers.rake:11:in `block (2 levels) in <main>'
Tasks: TOP => test:carriers
(See full trace by running task with --trace)
The error appeared with no changes to our tests or environment configuration. (Running a full rake worked just fine.)
When reviewing the source code for Rails::TestUnit::Runner, I came across rake_run. Simply replacing Rails::TestUnit::Runner.run with Rails::TestUnit::Runner.rake_run addressed the issue (no other changes required):
# lib/tasks/carrier.rake
namespace :test do
task carriers: "test:prepare" do
$: << "test"
test_files = FileList["test/models/carrier_test.rb",
"test/controllers/admin/carriers/**/*_test.rb",
"test/system/admin/carriers/**/*_test.rb"]
Rails::TestUnit::Runner.rake_run(test_files)
end
end

How can I fix the "class variable ##debug_missing_translation of ActionView::Base is overtaken by Object" error when running any task with ruby 3.0?

I am trying to upgrade a Rails 6.1.3.1 application from Ruby 2.6.6 to 3.0.0
All the rspec tests run fine and the in development everything seems to work just fine except one thing:
Even the simplest of tasks fails with this error:
"class variable ##debug_missing_translation of ActionView::Base is overtaken by Object"
For example, this simpletask.rake file
task simpletask: :environment do
puts 'Hello'
end
is not able to run as I get the following error:
lxxx#xxx:~/Workspace/edumino$ rails simpletask
rails aborted!
class variable ##debug_missing_translation of ActionView::Base is overtaken by Object
/home/xxx/railsapp/config/environment.rb:5:in `<top (required)>'
/home/xxx/railsapp/bin/rails:5:in `require'
/home/xxx/railsapp/bin/rails:5:in `<top (required)>'
/home/xxx/railsapp/bin/spring:10:in `require'
/home/xxx/railsapp/bin/spring:10:in `block in <top (required)>'
/home/xxx/railsapp/bin/spring:7:in `<top (required)>'
Tasks: TOP => simpletask => environment
(See full trace by running task with --trace)
...so, it turns out the problem was an already existing task. I don't remember exactly why this was necessary but the task had this:
# frozen_string_literal: true
require "#{Rails.root}/app/helpers/cron_helper"
require "#{Rails.root}/app/helpers/notifier_helper"
require "#{Rails.root}/app/helpers/application_helper"
include ApplicationHelper
include ActionView::Helpers::TranslationHelper
include CronHelper
namespace :cron do
task sms: :environment do |_t, _args|
...
end
end
I assume that the guilty code was including the ActionView::Helpers::TranslationHelper
Again, I can't remember why I had to do that at that time. But if you bump into this kind of 'overtaken by' error when upgrading to Ruby 3.0, check your other tasks and see what kinda weird includes you might have had. In my case, since I didn't need the old task, I just removed it.

Where is db:create defined in Rails?

The following command is supposed to create a new database.
rails db:create
Where is this function defined? Or is this a pre-packaged function in rails?
It's in the databases.rake file of the framework:
namespace :create do
task all: :load_config do
ActiveRecord::Tasks::DatabaseTasks.create_all
end
ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
desc "Create #{spec_name} database for current environment"
task spec_name => :load_config do
db_config = ActiveRecord::DatabaseConfigurations.config_for_env_and_spec(Rails.env, spec_name)
ActiveRecord::Tasks::DatabaseTasks.create(db_config.config)
end
end
end
Whenever you doubt or want to know where a task has been defined, you can use the rails -W (or rake) command, passing the task:
$ rails -W db:create
rails db:create /path/databases.rake:26:in `block in <top (required)>'
rails db:create:all /path/databases.rake:20:in `block (2 levels) in <top (required)>'
Note it was introduced in the version 0.9 of Rake. This might or might not work depending on the versions which you're working with.

Enhance assets:precompile on Heroku to add non fingerptinted filenames

In a Rails 4 app, I want precompiled assets to have copies of some assets to be available with a non fingerprinted filename. The app is deployed on Heroku.
I have the following rake task in place:
namespace :app do
task :nonfingerprint_assets => :environment do
manifests = Rails.application.config.assets[:precompile]
manifests = manifests.slice(1, manifests.length)
assets = Dir.glob(File.join(Rails.root, 'public/assets/**/*'))
regex = /(-{1}[a-z0-9]{32}*\.{1}){1}/
assets.each do |file|
next if File.directory?(file) || file !~ regex
source = file.split('/')
source.push(source.pop.gsub(regex, '.'))
non_digested = File.join(source)
if manifests.any? {|m|
if m.is_a? Regexp
m.match non_digested
else
m.ends_with?(non_digested)
end
}
puts "** copy source: #{file}"
puts "** copy destination: #{non_digested}"
FileUtils.cp(file, non_digested)
end
end
end
end
Rake::Task['assets:precompile'].enhance do
puts "Invoke nonfingerprint_assets"
Rake::Task['app:nonfingerprint_assets'].invoke
end
This rake task is working fine on my local machine even in production environment. It creates a file in public/assets/application.js which is the copy of the same file with a digest in its name.
When I deploy this code to heroku I get the following error message which I don't understand:
-----> Preparing app for Rails asset pipeline
Running: rake assets:precompile
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_
locales = false to avoid this message.
Invoke nonfingerprint_assets
** copy source: /tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/public/assets/application-51d1660b66655782ab137ee98c789fdd.js
** copy destination: /tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/public/assets/application.js
rake aborted!
No such file or directory - /tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/public/assets/application.js
/tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/lib/tasks/production.rake:26:in `block (3 levels) in <top (required)>'
/tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/lib/tasks/production.rake:9:in `each'
/tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/lib/tasks/production.rake:9:in `block (2 levels) in <top (required)>'
/tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/lib/tasks/production.rake:45:in `block in <top (required)>'
Tasks: TOP => app:nonfingerprint_assets
(See full trace by running task with --trace)
Please help me to understand what's going on.

Resources