From 3b29ce2bb264cc1635d2fb5952e760b5ea37fdeb Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 4 Sep 2026 08:30:05 +0000 Subject: [PATCH] Report a failing Ember suite instead of exiting the process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Shell#test` ran `ember test` through `Runner#run!`, which exits the calling process when the command fails. `App#test` therefore could never return the `false` its `success?` call promises: any consumer running the suite from Ruby — RSpec included — was terminated mid-run, with an exit and a partial summary instead of a test failure. Run the suite with `Runner#run` and return the status, so `App#test` reports the outcome to its caller. `EmberCli.test!` now raises `EmberCli::TestFailureError` when a suite fails, so library consumers can rescue the failure in Ruby, while the exception still exits `rake ember:test` nonzero. `Runner#run!` keeps its exiting behavior for `compile` and `install`, whose rake tasks rely on it. Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 9 ++++++++ lib/ember_cli.rb | 6 +++++- lib/ember_cli/errors.rb | 1 + lib/ember_cli/shell.rb | 2 +- spec/lib/ember_cli/shell_spec.rb | 35 ++++++++++++++++++++++++++++++++ spec/lib/ember_cli_spec.rb | 27 ++++++++++++++++++++++++ 6 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 spec/lib/ember_cli/shell_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index c7e3ace1..00e7542d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +main +------ + +* Fix `EmberCli::App#test` to report a failing suite by returning `false` + instead of exiting the process from inside the gem — one failing Ember suite + no longer aborts the caller (RSpec included) mid-run. `EmberCli.test!` + raises `EmberCli::TestFailureError` when a suite fails, which still exits + `rake ember:test` nonzero + 0.13.0 ------ diff --git a/lib/ember_cli.rb b/lib/ember_cli.rb index 8315a374..e8c8976e 100644 --- a/lib/ember_cli.rb +++ b/lib/ember_cli.rb @@ -44,7 +44,11 @@ def install_dependencies! end def test! - each_app(&:test) + each_app do |app| + unless app.test + fail TestFailureError, "The Ember test suite failed for #{app.name.inspect}" + end + end end def compile! diff --git a/lib/ember_cli/errors.rb b/lib/ember_cli/errors.rb index a72f9ee9..9a624334 100644 --- a/lib/ember_cli/errors.rb +++ b/lib/ember_cli/errors.rb @@ -1,4 +1,5 @@ module EmberCli class BuildError < StandardError; end class DependencyError < BuildError; end + class TestFailureError < StandardError; end end diff --git a/lib/ember_cli/shell.rb b/lib/ember_cli/shell.rb index 8bc81672..fa6aef26 100644 --- a/lib/ember_cli/shell.rb +++ b/lib/ember_cli/shell.rb @@ -81,7 +81,7 @@ def install end def test - run! ember.test + run ember.test end private diff --git a/spec/lib/ember_cli/shell_spec.rb b/spec/lib/ember_cli/shell_spec.rb new file mode 100644 index 00000000..72a05599 --- /dev/null +++ b/spec/lib/ember_cli/shell_spec.rb @@ -0,0 +1,35 @@ +require "ember_cli/shell" + +describe EmberCli::Shell do + describe "#test" do + it "returns a successful status when the suite passes" do + shell = build_shell(ember: "true") + + status = shell.test + + expect(status).to be_success + end + + it "returns an unsuccessful status when the suite fails" do + shell = build_shell(ember: "false") + + status = shell.test + + expect(status).not_to be_success + end + end + + # The `ember` executable is the seam: `Command#test` builds the command + # line from it, so `true` and `false` stand in for a passing and a failing + # `ember test` run. + def build_shell(ember:) + paths = double( + "EmberCli::PathSet", + ember: ember, + root: Pathname.new(Dir.pwd), + log: Pathname.new(File::NULL), + ) + + EmberCli::Shell.new(paths: paths) + end +end diff --git a/spec/lib/ember_cli_spec.rb b/spec/lib/ember_cli_spec.rb index f2d18575..c7d9c4e4 100644 --- a/spec/lib/ember_cli_spec.rb +++ b/spec/lib/ember_cli_spec.rb @@ -12,6 +12,33 @@ end end + describe ".test!" do + it "runs every application's test suite" do + passing = test_app(name: "passing", passed: true) + also_passing = test_app(name: "also-passing", passed: true) + stub_apps(passing: passing, also_passing: also_passing) + + EmberCli.test! + + expect(passing).to have_received(:test) + expect(also_passing).to have_received(:test) + end + + it "raises when an application's test suite fails" do + failing = test_app(name: "failing", passed: false) + stub_apps(failing: failing) + + expect { EmberCli.test! }.to raise_error( + EmberCli::TestFailureError, + /"failing"/, + ) + end + + def test_app(name:, passed:) + instance_double(EmberCli::App, name: name, test: passed) + end + end + def stub_apps(applications) allow(EmberCli).to receive(:apps).and_return(applications) end