Just upgrading a Rails 7.2.2 app to Rails 8.0.1. Before the upgrade, all tests run cleanly. App was upgraded to ruby 3.4.2 just before (and all tests passed with no warnings). After upgrade, this warning is emitted:
/home/<username>/.asdf/installs/ruby/3.4.2/lib/ruby/gems/3.4.0/gems/railties-8.0.1/lib/rails/tasks/statistics.rake:4: warning: already initialized constant STATS_DIRECTORIES Time: 00:00:10, ETA: 00:03:50
/home/<username>/.asdf/installs/ruby/3.4.2/lib/ruby/gems/3.4.0/gems/railties-8.0.1/lib/rails/tasks/statistics.rake:4: warning: previous definition of STATS_DIRECTORIES was here
I have traced the issue to one test suite for a Rake Task that is run regularly in production by Heroku Scheduler.
The test looks like:
require "test_helper"
class TimedEmailsTaskTest < ActionDispatch::IntegrationTest
setup do
Rails.application.load_tasks
@my_object = create(:object)
end
teardown do
ActionMailer::Base.deliveries.clear
Rake::Task["my_regular_emails_task"].reenable
end
... 4 tests that assert things using Rake::Task["my_regular_emails_task"].invoke ...
end
The offending line is Rails.application.load_tasks
, which I tracked down with the help of this github issue. Originally the warning was emitted once for each test in this suite; I can get it down to once by using:
Rails.application.load_tasks unless defined?(Rake::Task) && Rake::Task.tasks.any?
With the help of some good old puts debugging, I have tracked the initial "hit" on statistics.rake:4
to my Rakefile (in the app root directory), which is the standard default file:
require_relative "config/application"
Rails.application.load_tasks
So, the Rakefile runs, sets the constant STATS_DIRECTORIES, but the tasks aren't available in tests without running Rails.application.load_tasks
again, which emits the warning. Interestingly, If I just run the single test file, the Rakefile doesn't run and warning isn't emitted; it only happens when running multiple tests (e.g. rails test
or rails test:integration
).
I have spent a few hours with this, including trying to move statements to test_helper.rb with no meaningful change in the outcome. I'm also unhappy with the possibility of creating flaky tests that either emit a warning when running the suite and pass silently when running the one file, or fail when running the one file and pass (with warning) when running the full suite. I'm somewhat confused about how Rakefile
works and when it runs, and confused why this wasn't an issue on Rails 7. Is there an insight I'm missing? Is there an obvious misconfiguration here or more idiomatic approach that would solve this?
PS: This same railties line was emitting warnings for people back on Rails 4, but that question was never resolved so isn't much help.
EDIT:
The revised task looks like:
# ./lib/tasks/emails.rake
desc "send all notification emails"
task send_timed_email_notices: :environment do
TimedEmailNotices.send_all
end
I had the same problem when testing rake tasks. The following example works for me:
require 'test_helper'
require 'rake'
class PersonTaskTest < ActiveSupport::TestCase
def setup
Rake.application.rake_require('tasks/person')
Rake::Task.define_task(:environment)
end
def teardown
Rake::Task.clear
end
test "person:seed_10 create 10 people" do
initial_count = Person.count
Rake::Task["person:seed_10"].reenable
Rake::Task["person:seed_10"].invoke
assert_equal initial_count + 10, Person.count
end
end