Skip to content

Commit bc9c665

Browse files
andrewn617gmcgibbon
andcommitted
Allow Actionable Errors encountered when running tests to be retried.
If running in an interactive console, the user will be given the option to correct the error and re-run the tests. Co-authored-by: Gannon McGibbon <[email protected]>
1 parent 02f6c29 commit bc9c665

File tree

5 files changed

+93
-7
lines changed

5 files changed

+93
-7
lines changed

railties/CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
1+
* Allow Actionable Errors encountered when running tests to be retried.
2+
3+
```txt
4+
Migrations are pending. To resolve this issue, run:
5+
6+
bin/rails db:migrate
7+
8+
You have 1 pending migration:
9+
10+
db/migrate/20240201213806_add_a_to_b.rb
11+
Run pending migrations? [Yn] Y
12+
== 20240201213806 AddAToB: migrating =========================================
13+
== 20240201213806 AddAToB: migrated (0.0000s) ================================
14+
15+
Running 7 tests in a single process (parallelization threshold is 50)
16+
Run options: --seed 22200
17+
18+
# Running:
19+
20+
.......
21+
22+
Finished in 0.243394s, 28.7600 runs/s, 45.1942 assertions/s.
23+
7 runs, 11 assertions, 0 failures, 0 errors, 0 skips
24+
```
25+
26+
This feature will only be present on interactive terminals.
27+
28+
*Andrew Novoselac & Gannon McGibbon*
29+
130
* Skip generating a `test` job in ci.yml when a new application is generated with the
231
`--skip-test` option.
332

railties/lib/rails/command/base.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,26 @@ def invoke_command(command, *) # :nodoc:
179179
ensure
180180
@current_subcommand = original_subcommand
181181
end
182+
183+
protected
184+
def with_actionable_errors_retried(&block)
185+
block.call
186+
rescue ActiveSupport::ActionableError => e
187+
puts e.to_s.strip
188+
exit 1 unless tty?
189+
190+
ActiveSupport::ActionableError.actions(e).each_key do |action_name|
191+
if yes? "#{action_name}? [Yn]"
192+
ActiveSupport::ActionableError.dispatch(e, action_name)
193+
return with_actionable_errors_retried(&block)
194+
end
195+
end
196+
exit 1
197+
end
198+
199+
def tty?
200+
STDOUT.tty?
201+
end
182202
end
183203
end
184204
end

railties/lib/rails/commands/test/test_command.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ def perform(*args)
3030

3131
Rails::TestUnit::Runner.parse_options(args)
3232
run_prepare_task if self.args.none?(EXACT_TEST_ARGUMENT_PATTERN)
33-
Rails::TestUnit::Runner.run(args)
33+
with_actionable_errors_retried do
34+
Rails::TestUnit::Runner.run(args)
35+
end
3436
rescue Rails::TestUnit::InvalidTestError => error
3537
say error.message
3638
end

railties/lib/rails/testing/maintain_test_schema.rb

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
# frozen_string_literal: true
22

33
if defined?(ActiveRecord::Base)
4-
begin
5-
ActiveRecord::Migration.maintain_test_schema!
6-
rescue ActiveRecord::PendingMigrationError => e
7-
puts e.to_s.strip
8-
exit 1
9-
end
4+
5+
ActiveRecord::Migration.maintain_test_schema!
106

117
if Rails.configuration.eager_load
128
ActiveRecord::Base.descendants.each do |model|

railties/test/application/test_test.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,45 @@ def self.load_schema!
345345
assert_unsuccessful_run "models/user_test.rb", "SCHEMA LOADED!"
346346
end
347347

348+
def test_actionable_command_line_error_with_tty
349+
rails "generate", "scaffold", "user", "name:string"
350+
app_file "config/initializers/thor_yes.rb", <<-RUBY
351+
Rails::Command::Base.class_eval <<-INITIALIZER
352+
def yes?(statement, color = nil)
353+
raise ArgumentError unless statement == "Run pending migrations? [Yn]"
354+
true
355+
end
356+
357+
def tty?
358+
true
359+
end
360+
INITIALIZER
361+
RUBY
362+
363+
run_test_file("models/user_test.rb").tap do |output|
364+
assert_match "Migrations are pending. To resolve this issue, run:", output
365+
assert_match "CreateUsers: migrating", output
366+
assert_match "0 runs, 0 assertions, 0 failures, 0 errors, 0 skips", output
367+
end
368+
end
369+
370+
def test_actionable_command_line_without_tty
371+
rails "generate", "scaffold", "user", "name:string"
372+
app_file "config/initializers/thor_yes.rb", <<-RUBY
373+
Rails::Command::Base.class_eval <<-INITIALIZER
374+
def tty?
375+
false
376+
end
377+
INITIALIZER
378+
RUBY
379+
380+
run_test_file("models/user_test.rb").tap do |output|
381+
assert_match "Migrations are pending. To resolve this issue, run:", output
382+
assert_no_match "CreateUsers: migrating", output
383+
assert_no_match "0 runs, 0 assertions, 0 failures, 0 errors, 0 skips", output
384+
end
385+
end
386+
348387
private
349388
def assert_unsuccessful_run(name, message)
350389
result = run_test_file(name)

0 commit comments

Comments
 (0)