How to invoke RSpec inside a rake task? - ruby-on-rails

We wrote some tests that are necessary, but very slow. So we configured RSpec to exclude them except on Solano, where we set up an ENV variable.
# spec_helper
unless ENV['RUN_ALL_TESTS'] == 'true'
config.filter_run_excluding :slow
end
That works, but I'm trying to write a rake task we can call to run every test locally by setting that same ENV variable and then running the suite. I'm having trouble figuring out how to trigger RSpec. This is what I've got now:
# all_tests.rake
require 'rspec/core/rake_task'
desc 'Run all tests, even those usually excluded.'
task all_tests: :environment do
ENV['RUN_ALL_TESTS'] = 'true'
RSpec::Core::RakeTask.new(:spec)
end
When I run it, it doesn't run any tests.
Most of the stuff I found is for triggering a rake task inside of a test, testing a rake task, or setting up a Rakefile. We're using rspec-rails, our default rake task is already set up.

To run RSpec through its rake integration, you need to both define a task and invoke it:
# all_tests.rake
require 'rspec/core/rake_task'
# Define the "spec" task, at task load time rather than inside another task
RSpec::Core::RakeTask.new(:spec)
desc 'Run all tests, even those usually excluded.'
task all_tests: :environment do
ENV['RUN_ALL_TESTS'] = 'true'
Rake::Task['spec'].invoke
end
Rake::Task['spec'].invoke did nothing when you tried it because rake turns a task name which is not a name of a defined task but is a file name into a Rake::FileTask, both on the command line and in Rake::Task. You had no 'spec' task defined, but you have a spec directory, so rake spec ran without error and did nothing.

I had a similar problem where bundle exec rake default would properly create an RSpec::Core::RakeTask, but bundle exec rake spec would instead create a a Rake::FileTask on the spec directory, with with bundle exec rake spec --trace outputting:
** Invoke spec (first_time, not_needed)
It turned out that rspec-rails was in the :test gem group, where it needed (per the docs) to be in both :test and :development.
Interestingly (?), once I did that, gems that had previously only been in the :test group were also available from the specs even when launched with RAILS_ENV=development. I assume that rspec-rails engages in some magic environment shenanigans behind the scenes.

Related

When switching from Minitest to RSpec in Rails, how to make `rails test` (or `rake test`) run the RSpec tests?

When adding RSpec to Rails, we can finally run rails spec (or bundle exec rspec) to run the RSpec tests.
However, rails test confusingly still attempts to run the (non-existent) Minitest tests.
How can the "test" rake task be configured to run the RSpec tests instead?
You can override the test task like this:
# Add the code below in the Rakefile
require File.expand_path(‘config/application’, __dir__)
Rails.application.load_tasks
Rake::Task['test'].clear
task :test do
Rake::Task['rspec’].invoke
end
Another way (I only tried in my console with a task that puts something but it should work with rspec):
# Add the code below in the Rakefile
require File.expand_path(‘config/application’, __dir__)
Rails.application.load_tasks
task(:test).clear.enhance([‘rspec’])

Change Rails/Rake Test Default Behavior

According to the Rails guide for testing:
"By default, running bin/rails test won't run your system tests. Make sure to run bin/rails test:system to actually run them."
Does anyone know how to change the default behavior so it will run all of your tests including system tests?
I'm trying to do the same.
I think that for having rails test to also run system tests you need to redefine the rake task. For what I could investigate the task is defined at testing.rake file inside the railties gem /lib directory:
desc "Runs all tests in test folder except system ones"
task :test do
$: << "test"
if ENV.key?("TEST")
Minitest.rake_run([ENV["TEST"]])
else
Minitest.rake_run(["test"], ["test/system/**/*"])
end
end
The second argument in the function inside else is a pattern to exclude when running the tests.
Here Overriding rails' default rake tasks
it's explained how to override them, however I couldn't put it to work this way.
If it helps you, I'm using bundle exec rake test:system test instead and it runs both the system and all the other tests together

Can I run just tests inside a subfolder of the test folder in Rails (Minitest)?

Hard to believe this hasn't been asked before, but I couldn't find it.
I am trying to run only my Capybara tests who are inside their own folder test/integration/capybara.
I tried to do it by bundle exec rake test test/integration/capybara but it always runs all the tests under test.
In the Rails Guides it says I can invoke just my integration tests by rake test:integration which works. But rake test test:integration:capybara doesn't.
Is it possible to go deeper than one level?
You can build your own rake task. Add that to lib/tasks/test_capybara.rake:
namespace :test do
namespace :integration do
Rake::TestTask.new('capybara') do |t|
t.libs = ['lib','test']
t.pattern = 'integration/capybara/**/*_test.rb'
t.verbose = true
end
end
end
Then run rake test test:integration:capybara.

Rails - Rake test and rubocop in one task

I'm trying to setup my rails project so that all the verification required by a contributor is in one command, currently we have been running:
rake test
But now we also want to use rubocop for static analysis:
rubocop -R -a
I want this to be executable in one simple rake task. It would be nice to override 'rake test' to run rubocop then the standard rake test stuff for a rails project, as then no-one will have to remember to change the command. But if I have to create a separate rake task, that's probably fine too.
I've seen the rubocop rake integration here, at the bottom, but I'm not sure how to bundle that with 'rake test' into one task... Any thoughts?
I prefer to set my default task to run rubocop then the tests. Either way, it is a good idea to have those tasks separate rather than have one task do two things.
require 'rubocop/rake_task'
task :default => [:rubocop, :test]
desc 'Run tests'
task(:test) do
# run your specs here
end
desc 'Run rubocop'
task :rubocop do
RuboCop::RakeTask.new
end
Your tasks:
> rake -T
rake rubocop # Run rubocop
rake test # Run tests
This is the .rake file that I ended up with in the end.
desc 'Run tests and rubocop'
task :validate do
Rake::Task['rubocop'].invoke
Rake::Task['test'].invoke
end
task :rubocop do
require 'rubocop'
cli = Rubocop::CLI.new
cli.run(%w(--rails --auto-correct))
end
You could easily define your own rake task which first invokes Rails' test rake task and then the code snippet you mentioned for rubocop.
For example, in a .rake file you could have something like that:
require 'rubocop/rake_task'
desc 'Run tests and rubocop'
task :my_test do
Rake::Task['test'].invoke
RuboCop::RakeTask.new
end
If you feel the need to customize the call to Rubocop and that involves more code, you could create another custom task, say :rubocop, which you then invoke from :my_test as well.
Finally, an alternative to creating your own rake task and sticking with rake test would be to modify your test_helper to invoke whatever you need invoked after testing is completed.
It appears to have changed from:
Rubocop::RakeTask.new
to:
RuboCop::RakeTask.new
See ma? I know how to CamelCase!
I used following .rake file to run the test and rubocop tasks at once:
task default: %w[rubocop test]
RuboCop::RakeTask.new(:rubocop) do |task|
task.patterns = ['**/*.rb']
task.fail_on_error = false
task.options = ["--auto-correct-all"]
end
task :test do
ruby 'test/program_test.rb'
end
The first line allows both tasks to be run by calling rake.
Command line arguments can also be added in the options array.

Disable rake task

In our project, if you run rake test, terrible things happen; you need to run rake spec. I can't seem to figure out how to re-define rake test to just output a message suggesting running rake spec instead.
How can I do this?
On your Rakefile at the end:
Rake::Task["test"].clear
task 'test' do
puts "use 'rake spec'"
end
Or even better
Rake::Task["test"].clear
task 'test' do
Rake::Task["spec"].invoke
end

Resources