|
5 | 5 |
|
6 | 6 | RSpec.describe ReactOnRails::Dev::PackGenerator do |
7 | 7 | describe ".generate" do |
8 | | - it "runs pack generation successfully in verbose mode" do |
9 | | - allow(described_class).to receive(:system) |
10 | | - .with("bundle", "exec", "rake", "react_on_rails:generate_packs") |
11 | | - .and_return(true) |
| 8 | + context "when in Bundler context with Rails available" do |
| 9 | + let(:mock_task) { instance_double(Rake::Task) } |
| 10 | + let(:mock_rails_app) do |
| 11 | + # rubocop:disable RSpec/VerifiedDoubles |
| 12 | + double("Rails.application").tap do |app| |
| 13 | + allow(app).to receive(:load_tasks) |
| 14 | + allow(app).to receive(:respond_to?).with(:load_tasks).and_return(true) |
| 15 | + end |
| 16 | + # rubocop:enable RSpec/VerifiedDoubles |
| 17 | + end |
12 | 18 |
|
13 | | - expect { described_class.generate(verbose: true) } |
14 | | - .to output(/📦 Generating React on Rails packs.../).to_stdout_from_any_process |
| 19 | + before do |
| 20 | + # Setup Bundler context |
| 21 | + stub_const("Bundler", Module.new) |
| 22 | + allow(ENV).to receive(:[]).and_call_original |
| 23 | + allow(ENV).to receive(:[]).with("BUNDLE_GEMFILE").and_return("/path/to/Gemfile") |
| 24 | + |
| 25 | + # Setup Rails availability |
| 26 | + app = mock_rails_app |
| 27 | + rails_module = Module.new do |
| 28 | + define_singleton_method(:application) { app } |
| 29 | + define_singleton_method(:respond_to?) { |method, *| method == :application } |
| 30 | + end |
| 31 | + stub_const("Rails", rails_module) |
| 32 | + |
| 33 | + # Mock Rake::Task at the boundary |
| 34 | + allow(Rake::Task).to receive(:task_defined?).with("react_on_rails:generate_packs").and_return(false) |
| 35 | + allow(Rake::Task).to receive(:[]).with("react_on_rails:generate_packs").and_return(mock_task) |
| 36 | + allow(mock_task).to receive(:reenable) |
| 37 | + allow(mock_task).to receive(:invoke) |
| 38 | + end |
| 39 | + |
| 40 | + it "runs pack generation successfully in verbose mode using direct rake execution" do |
| 41 | + expect { described_class.generate(verbose: true) } |
| 42 | + .to output(/📦 Generating React on Rails packs.../).to_stdout_from_any_process |
| 43 | + |
| 44 | + expect(mock_task).to have_received(:invoke) |
| 45 | + expect(mock_rails_app).to have_received(:load_tasks) |
| 46 | + end |
| 47 | + |
| 48 | + it "runs pack generation successfully in quiet mode using direct rake execution" do |
| 49 | + expect { described_class.generate(verbose: false) } |
| 50 | + .to output(/📦 Generating packs\.\.\. ✅/).to_stdout_from_any_process |
| 51 | + |
| 52 | + expect(mock_task).to have_received(:invoke) |
| 53 | + end |
| 54 | + |
| 55 | + it "exits with error when pack generation fails" do |
| 56 | + allow(mock_task).to receive(:invoke).and_raise(StandardError.new("Task failed")) |
| 57 | + |
| 58 | + # Mock STDERR.puts to capture output |
| 59 | + error_output = [] |
| 60 | + # rubocop:disable Style/GlobalStdStream |
| 61 | + allow(STDERR).to receive(:puts) { |msg| error_output << msg } |
| 62 | + # rubocop:enable Style/GlobalStdStream |
| 63 | + |
| 64 | + expect { described_class.generate(verbose: false) }.to raise_error(SystemExit) |
| 65 | + expect(error_output.join("\n")).to match(/Error generating packs: Task failed/) |
| 66 | + end |
| 67 | + |
| 68 | + it "outputs errors to stderr even in silent mode" do |
| 69 | + allow(mock_task).to receive(:invoke).and_raise(StandardError.new("Silent mode error")) |
| 70 | + |
| 71 | + # Mock STDERR.puts to capture output |
| 72 | + error_output = [] |
| 73 | + # rubocop:disable Style/GlobalStdStream |
| 74 | + allow(STDERR).to receive(:puts) { |msg| error_output << msg } |
| 75 | + # rubocop:enable Style/GlobalStdStream |
| 76 | + |
| 77 | + expect { described_class.generate(verbose: false) }.to raise_error(SystemExit) |
| 78 | + expect(error_output.join("\n")).to match(/Error generating packs: Silent mode error/) |
| 79 | + end |
| 80 | + |
| 81 | + it "includes backtrace in error output when DEBUG env is set" do |
| 82 | + allow(ENV).to receive(:[]).with("DEBUG").and_return("true") |
| 83 | + allow(mock_task).to receive(:invoke).and_raise(StandardError.new("Debug error")) |
| 84 | + |
| 85 | + # Mock STDERR.puts to capture output |
| 86 | + error_output = [] |
| 87 | + # rubocop:disable Style/GlobalStdStream |
| 88 | + allow(STDERR).to receive(:puts) { |msg| error_output << msg } |
| 89 | + # rubocop:enable Style/GlobalStdStream |
| 90 | + |
| 91 | + expect { described_class.generate(verbose: false) }.to raise_error(SystemExit) |
| 92 | + expect(error_output.join("\n")).to match(/Error generating packs: Debug error.*pack_generator_spec\.rb/m) |
| 93 | + end |
| 94 | + |
| 95 | + it "suppresses stdout in silent mode" do |
| 96 | + # Mock task to produce output |
| 97 | + allow(mock_task).to receive(:invoke) do |
| 98 | + puts "This should be suppressed" |
| 99 | + end |
| 100 | + |
| 101 | + expect { described_class.generate(verbose: false) } |
| 102 | + .not_to output(/This should be suppressed/).to_stdout_from_any_process |
| 103 | + end |
15 | 104 | end |
16 | 105 |
|
17 | | - it "runs pack generation successfully in quiet mode" do |
18 | | - allow(described_class).to receive(:system) |
19 | | - .with("bundle", "exec", "rake", "react_on_rails:generate_packs", out: File::NULL, err: File::NULL) |
20 | | - .and_return(true) |
| 106 | + context "when not in Bundler context" do |
| 107 | + before do |
| 108 | + # Ensure we're not in Bundler context |
| 109 | + hide_const("Bundler") if defined?(Bundler) |
| 110 | + end |
| 111 | + |
| 112 | + it "runs pack generation successfully in verbose mode using bundle exec" do |
| 113 | + allow(described_class).to receive(:system) |
| 114 | + .with("bundle", "exec", "rake", "react_on_rails:generate_packs") |
| 115 | + .and_return(true) |
| 116 | + |
| 117 | + expect { described_class.generate(verbose: true) } |
| 118 | + .to output(/📦 Generating React on Rails packs.../).to_stdout_from_any_process |
| 119 | + |
| 120 | + expect(described_class).to have_received(:system) |
| 121 | + .with("bundle", "exec", "rake", "react_on_rails:generate_packs") |
| 122 | + end |
| 123 | + |
| 124 | + it "runs pack generation successfully in quiet mode using bundle exec" do |
| 125 | + allow(described_class).to receive(:system) |
| 126 | + .with("bundle", "exec", "rake", "react_on_rails:generate_packs", |
| 127 | + out: File::NULL, err: File::NULL) |
| 128 | + .and_return(true) |
21 | 129 |
|
22 | | - expect { described_class.generate(verbose: false) } |
23 | | - .to output(/📦 Generating packs\.\.\. ✅/).to_stdout_from_any_process |
| 130 | + expect { described_class.generate(verbose: false) } |
| 131 | + .to output(/📦 Generating packs\.\.\. ✅/).to_stdout_from_any_process |
| 132 | + |
| 133 | + expect(described_class).to have_received(:system) |
| 134 | + .with("bundle", "exec", "rake", "react_on_rails:generate_packs", |
| 135 | + out: File::NULL, err: File::NULL) |
| 136 | + end |
| 137 | + |
| 138 | + it "exits with error when pack generation fails" do |
| 139 | + allow(described_class).to receive(:system) |
| 140 | + .with("bundle", "exec", "rake", "react_on_rails:generate_packs", |
| 141 | + out: File::NULL, err: File::NULL) |
| 142 | + .and_return(false) |
| 143 | + |
| 144 | + expect { described_class.generate(verbose: false) }.to raise_error(SystemExit) |
| 145 | + end |
24 | 146 | end |
25 | 147 |
|
26 | | - it "exits with error when pack generation fails" do |
27 | | - allow(described_class).to receive(:system) |
28 | | - .with("bundle", "exec", "rake", "react_on_rails:generate_packs", out: File::NULL, err: File::NULL) |
29 | | - .and_return(false) |
| 148 | + context "when Rails is not available" do |
| 149 | + before do |
| 150 | + stub_const("Bundler", Module.new) |
| 151 | + allow(ENV).to receive(:[]).and_call_original |
| 152 | + allow(ENV).to receive(:[]).with("BUNDLE_GEMFILE").and_return("/path/to/Gemfile") |
| 153 | + |
| 154 | + # Rails not available |
| 155 | + hide_const("Rails") if defined?(Rails) |
| 156 | + end |
| 157 | + |
| 158 | + it "falls back to bundle exec when Rails is not defined" do |
| 159 | + allow(described_class).to receive(:system) |
| 160 | + .with("bundle", "exec", "rake", "react_on_rails:generate_packs") |
| 161 | + .and_return(true) |
| 162 | + |
| 163 | + expect { described_class.generate(verbose: true) } |
| 164 | + .to output(/📦 Generating React on Rails packs.../).to_stdout_from_any_process |
30 | 165 |
|
31 | | - expect { described_class.generate(verbose: false) }.to raise_error(SystemExit) |
| 166 | + expect(described_class).to have_received(:system) |
| 167 | + .with("bundle", "exec", "rake", "react_on_rails:generate_packs") |
| 168 | + end |
32 | 169 | end |
33 | 170 | end |
34 | 171 | end |
0 commit comments